/* * Copyright 2013-2014 the original author or authors. * * 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 org.springframework.xd.dirt.rest; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.ArrayList; import java.util.Arrays; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.xd.dirt.core.DeploymentUnitStatus; import org.springframework.xd.dirt.module.ModuleRegistry; import org.springframework.xd.dirt.module.WritableModuleRegistry; import org.springframework.xd.dirt.plugins.job.DistributedJobLocator; import org.springframework.xd.dirt.stream.JobDefinition; import org.springframework.xd.dirt.stream.JobDefinitionRepository; import org.springframework.xd.dirt.stream.JobRepository; import org.springframework.xd.module.ModuleDefinition; import org.springframework.xd.module.ModuleType; import org.springframework.xd.module.TestModuleDefinitions; /** * Tests REST compliance of jobs-related endpoints. * * @author Glenn Renfro * @author Ilayaperumal Gopinathan * @author Mark Fisher * @author Florent Biville */ @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = {RestConfiguration.class, Dependencies.class}) public class JobsControllerIntegrationTests extends AbstractControllerIntegrationTest { private static final String JOB_DEFINITION = "job --cron='*/10 * * * * *'"; @Autowired private ModuleRegistry moduleRegistry; @Autowired private WritableModuleRegistry writeableModuleRegistry; @Autowired private JobDefinitionRepository jobDefinitionRepository; @Autowired private JobRepository xdJobRepository; @Autowired private DistributedJobLocator jobLocator; @Before public void before() { ModuleDefinition moduleJobDefinition = TestModuleDefinitions.dummy("job", ModuleType.job); ArrayList<ModuleDefinition> moduleDefinitions = new ArrayList<ModuleDefinition>(); moduleDefinitions.add(moduleJobDefinition); when(moduleRegistry.findDefinitions("job")).thenReturn(moduleDefinitions); when(moduleRegistry.findDefinitions("job1")).thenReturn(moduleDefinitions); when(moduleRegistry.findDefinitions("job2")).thenReturn(moduleDefinitions); when(moduleRegistry.findDefinition("job1", ModuleType.job)).thenReturn(moduleJobDefinition); when(moduleRegistry.findDefinition("job2", ModuleType.job)).thenReturn(moduleJobDefinition); when(moduleRegistry.findDefinition("job", ModuleType.job)).thenReturn(moduleJobDefinition); when(jobLocator.getJobNames()).thenReturn(Arrays.asList(new String[] {})); ModuleDefinition any = Mockito.any(); when(writeableModuleRegistry.registerNew(any)).thenReturn(true); } @After public void cleanUp() { jobDefinitionRepository.deleteAll(); xdJobRepository.deleteAll(); } @Test public void testSuccessfulJobCreation() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); } @Test public void testComposedJobCreation() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", "A || B").accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); } @Test public void testComposedJobCreationBadDSL() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", "A || B >").accept( MediaType.APPLICATION_JSON)).andExpect(status().isInternalServerError()); } @Test public void testSuccessfulJobCreateAndDeploy() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job5").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); JobDefinition jobDefinition = jobDefinitionRepository.findOne("job5"); assertNotNull(jobDefinition); assertEquals("job5", jobDefinition.getName()); assertNotNull(xdJobRepository.findOne(jobDefinition.getName())); } @Test public void testSuccessfulJobDeletion() throws Exception { mockMvc.perform(delete("/jobs/definitions/{name}", "job1")); mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform(delete("/jobs/definitions/{name}", "job1")).andExpect(status().isOk()); } @Test public void testListAllJobs() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform( post("/jobs/definitions").param("name", "job2").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform(get("/jobs/definitions").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect( jsonPath("$.content", Matchers.hasSize(2))).andExpect(jsonPath("$.content[0].name").value("job1")).andExpect( jsonPath("$.content[1].name").value("job2")); } @Test public void testJobCreationNoDefinition() throws Exception { mockMvc.perform(post("/jobs/definitions").param("name", "myjob").accept(MediaType.APPLICATION_JSON)).andExpect( status().isBadRequest()); } @Test public void testJobUnDeployNoDef() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON).param("deploy", "false")).andExpect(status().isCreated()); mockMvc.perform(delete("/jobs/deployments/{name}", "myjob").accept(MediaType.APPLICATION_JSON)).andExpect( status().isNotFound()); } @Test public void testJobDeployNoDef() throws Exception { mockMvc.perform(post("/jobs/deployments/myjob").accept(MediaType.APPLICATION_JSON)).andExpect( status().isNotFound()); } @Test public void testCreateOnAlreadyCreatedJob() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); } @Test public void testFailedJobDeletion() throws Exception { mockMvc.perform(delete("/jobs/definitions/{name}", "job1")).andExpect(status().isNotFound()); } @Test public void testInvalidDefinitionCreate() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", "job adsfa").accept( MediaType.APPLICATION_JSON)).andExpect( status().isBadRequest()); mockMvc.perform(get("/jobs/definitions").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect( jsonPath("$.content", Matchers.hasSize(0))); } @Test public void testJobDestroyAll() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform( post("/jobs/definitions").param("name", "job2").param("definition", JOB_DEFINITION).accept( MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); assertNotNull(jobDefinitionRepository.findOne("job1")); assertNotNull(jobDefinitionRepository.findOne("job2")); // Perform destroy all mockMvc.perform(delete("/jobs/definitions").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); assertNull(jobDefinitionRepository.findOne("job1")); assertNull(jobDefinitionRepository.findOne("job2")); } @Test public void testJobThatAlreadyExistsInJobRepo() throws Exception { when(jobLocator.getJobNames()).thenReturn(Arrays.asList(new String[] {"mydupejob"})); mockMvc.perform( post("/jobs/definitions").param("name", "mydupejob").param("definition", "job adsfa").accept( MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()).andExpect( jsonPath("$[0].message", Matchers.is("Batch Job with the name mydupejob already exists"))); } @Test public void testCreatedUndeployedJobIsExposedAsUndeployed() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).param("deploy", "false") .accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform(get("/jobs/definitions/job1") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.status", equalTo(DeploymentUnitStatus.State.undeployed.toString()))); } @Test public void testCreatedAndDeployedJobIsExposedAsDeployed() throws Exception { mockMvc.perform( post("/jobs/definitions").param("name", "job1").param("definition", JOB_DEFINITION).param("deploy", "true") .accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); mockMvc.perform(get("/jobs/definitions/job1") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.status", equalTo(DeploymentUnitStatus.State.deploying.toString()))); } }