package de.otto.edison.jobs.controller; import de.otto.edison.jobs.domain.JobInfo; import de.otto.edison.jobs.service.JobMetaService; import de.otto.edison.jobs.service.JobService; import de.otto.edison.navigation.NavBar; import org.junit.Before; import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.time.OffsetDateTime; import java.time.ZoneId; import java.util.List; import java.util.Optional; import static de.otto.edison.jobs.controller.JobRepresentation.representationOf; import static de.otto.edison.jobs.domain.JobInfo.newJobInfo; import static java.time.Clock.fixed; import static java.time.Clock.systemDefaultZone; import static java.time.Instant.ofEpochMilli; import static java.time.ZoneId.systemDefault; import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; import static java.util.Arrays.asList; import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; public class JobsControllerTest { private JobService jobService; private JobMetaService jobMetaService; private MockMvc mockMvc; private JobsController jobsController; @Before public void setUp() throws Exception { jobService = mock(JobService.class); jobMetaService = mock(JobMetaService.class); jobsController = new JobsController(jobService, jobMetaService, mock(NavBar.class)); mockMvc = MockMvcBuilders .standaloneSetup(jobsController) .defaultRequest(MockMvcRequestBuilders.get("/").contextPath("/some-microservice")) .build(); } @Test public void shouldReturn404IfJobIsUnknown() throws Exception { // given when(jobService.findJob(any(String.class))).thenReturn(Optional.<JobInfo>empty()); // when mockMvc.perform(MockMvcRequestBuilders .get("/some-microservice/internal/jobs/42")) .andExpect(status().is(404)); } @Test public void shouldReturnJobIfJobExists() throws Exception { // given ZoneId cet = ZoneId.of("CET"); OffsetDateTime now = OffsetDateTime.now(cet); JobInfo expectedJob = newJobInfo("42", "TEST", fixed(now.toInstant(), cet), "localhost"); when(jobService.findJob("42")).thenReturn(Optional.of(expectedJob)); String nowAsString = ISO_OFFSET_DATE_TIME.format(now); mockMvc.perform(MockMvcRequestBuilders .get("/some-microservice/internal/jobs/42") .servletPath("/internal/jobs/42")) .andExpect(status().is(200)) .andExpect(jsonPath("$.status").value("OK")) .andExpect(jsonPath("$.messages").isArray()) .andExpect(jsonPath("$.jobType").value("TEST")) .andExpect(jsonPath("$.hostname").value("localhost")) .andExpect(jsonPath("$.started").value(nowAsString)) .andExpect(jsonPath("$.stopped").value("")) .andExpect(jsonPath("$.lastUpdated").value(nowAsString)) .andExpect(jsonPath("$.jobUri").value("http://localhost/some-microservice/internal/jobs/42")) .andExpect(jsonPath("$.links").isArray()) .andExpect(jsonPath("$.links[0].href").value("http://localhost/some-microservice/internal/jobs/42")) .andExpect(jsonPath("$.links[1].href").value("http://localhost/some-microservice/internal/jobdefinitions/TEST")) .andExpect(jsonPath("$.links[2].href").value("http://localhost/some-microservice/internal/jobs")) .andExpect(jsonPath("$.links[3].href").value("http://localhost/some-microservice/internal/jobs?type=TEST")) .andExpect(jsonPath("$.runtime").value("")) .andExpect(jsonPath("$.state").value("Running")); verify(jobService).findJob("42"); } @Test public void shouldReturnAllJobs() throws IOException { // given JobInfo firstJob = newJobInfo("42", "TEST", fixed(ofEpochMilli(0), systemDefault()), "localhost"); JobInfo secondJob = newJobInfo("42", "TEST", fixed(ofEpochMilli(1), systemDefault()), "localhost"); when(jobService.findJobs(Optional.<String>empty(), 100)).thenReturn(asList(firstJob, secondJob)); // when Object job = jobsController.getJobsAsJson(null, 100, false, mock(HttpServletRequest.class)); // then assertThat(job, is(asList(representationOf(firstJob, null, false, ""), representationOf(secondJob, null, false, "")))); } @Test public void shouldNotReturnAllJobsDistinctIfTypeIsGiven() throws IOException { // given JobInfo firstJob = newJobInfo("11", "jobType1", fixed(ofEpochMilli(0), systemDefault()), "localhost"); JobInfo secondJob = newJobInfo("12", "jobType2", fixed(ofEpochMilli(1), systemDefault()), "localhost"); JobInfo thirdJob = newJobInfo("13", "jobType3", fixed(ofEpochMilli(2), systemDefault()), "localhost"); JobInfo fourthJob = newJobInfo("14", "jobType2", fixed(ofEpochMilli(2), systemDefault()), "localhost"); when(jobService.findJobs(Optional.of("jobType2"), 100)).thenReturn(asList(secondJob, fourthJob)); // when Object job = jobsController.getJobsAsJson("jobType2", 100, true, mock(HttpServletRequest.class)); // then assertThat(job, is(asList(representationOf(secondJob, null, false, ""), representationOf(fourthJob, null, false, "")))); verify(jobService, times(1)).findJobs(Optional.of("jobType2"), 100); verifyNoMoreInteractions(jobService); } @Test public void shouldReturnAllJobsDistinct() throws IOException { // given JobInfo firstJob = newJobInfo("42", "jobType1", fixed(ofEpochMilli(0), systemDefault()), "localhost"); JobInfo secondJob = newJobInfo("42", "jobType2", fixed(ofEpochMilli(1), systemDefault()), "localhost"); JobInfo thirdJob = newJobInfo("42", "jobType3", fixed(ofEpochMilli(2), systemDefault()), "localhost"); when(jobService.findJobsDistinct()).thenReturn(asList(firstJob, secondJob, thirdJob)); // when Object job = jobsController.getJobsAsJson(null, 100, true, mock(HttpServletRequest.class)); // then assertThat(job, is(asList(representationOf(firstJob, null, false, ""), representationOf(secondJob, null, false, ""), representationOf(thirdJob, null, false, "")))); verify(jobService, times(1)).findJobsDistinct(); verifyNoMoreInteractions(jobService); } @Test @SuppressWarnings("unchecked") public void shouldReturnAllJobsOfTypeAsHtml() { JobInfo firstJob = newJobInfo("42", "SOME_TYPE", systemDefaultZone(), "localhost"); when(jobService.findJobs(Optional.of("SOME_TYPE"), 100)).thenReturn(asList(firstJob)); ModelAndView modelAndView = jobsController.getJobsAsHtml("SOME_TYPE", 100, false, mock(HttpServletRequest.class)); List<JobRepresentation> jobs = (List<JobRepresentation>) modelAndView.getModel().get("jobs"); assertThat(jobs, is(asList(representationOf(firstJob, null, false, "")))); } @Test public void shouldTriggerJobAndReturnItsURL() throws Exception { when(jobService.startAsyncJob("someJobType")).thenReturn(Optional.of("theJobId")); mockMvc.perform(MockMvcRequestBuilders .post("/some-microservice/internal/jobs/someJobType") .servletPath("/internal/jobs/someJobType")) .andExpect(status().is(204)) .andExpect(header().string("Location", "http://localhost/some-microservice/internal/jobs/theJobId")); verify(jobService).startAsyncJob("someJobType"); } @Test public void shouldDisableJob() throws Exception { mockMvc.perform(MockMvcRequestBuilders .post("/some-microservice/internal/jobs/someJobType/disable")) .andExpect(status().is(SC_MOVED_TEMPORARILY)) .andExpect(header().string("Location", "/some-microservice/internal/jobdefinitions")); verify(jobMetaService).disable("someJobType", null); } }