package de.otto.edison.jobs.repository; import de.otto.edison.jobs.domain.JobInfo; import de.otto.edison.jobs.domain.JobInfo.JobStatus; import de.otto.edison.jobs.domain.JobMessage; import de.otto.edison.jobs.domain.Level; import de.otto.edison.jobs.repository.inmem.InMemJobRepository; import org.hamcrest.Matchers; import org.hamcrest.collection.IsCollectionWithSize; import org.junit.Before; import org.junit.Test; import java.time.Clock; import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import static de.otto.edison.jobs.domain.JobInfo.JobStatus.ERROR; import static de.otto.edison.jobs.domain.JobInfo.JobStatus.OK; import static de.otto.edison.jobs.domain.JobInfo.builder; import static de.otto.edison.jobs.domain.JobInfo.newJobInfo; import static de.otto.edison.jobs.domain.JobMessage.jobMessage; import static de.otto.edison.testsupport.matcher.OptionalMatchers.isAbsent; import static de.otto.edison.testsupport.matcher.OptionalMatchers.isPresent; import static java.time.Clock.fixed; import static java.time.Clock.systemDefaultZone; import static java.time.OffsetDateTime.now; import static java.time.ZoneId.systemDefault; import static java.util.Arrays.asList; import static java.util.UUID.randomUUID; import static org.assertj.core.util.Lists.emptyList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; public class InMemJobRepositoryTest { InMemJobRepository repository; @Before public void setUp() throws Exception { repository = new InMemJobRepository(); } private Clock clock = systemDefaultZone(); @Test public void shouldFindJobInfoByUri() { // given InMemJobRepository repository = new InMemJobRepository(); // when JobInfo job = newJobInfo(randomUUID().toString(), "MYJOB", clock, "localhost"); repository.createOrUpdate(job); // then assertThat(repository.findOne(job.getJobId()), isPresent()); } @Test public void shouldReturnAbsentStatus() { InMemJobRepository repository = new InMemJobRepository(); assertThat(repository.findOne("some-nonexisting-job-id"), isAbsent()); } @Test public void shouldNotRemoveRunningJobs() { // given final String testUri = "test"; repository.createOrUpdate(newJobInfo(testUri, "FOO", systemDefaultZone(), "localhost")); // when repository.removeIfStopped(testUri); // then assertThat(repository.size(), is(1L)); } @Test public void shouldNotFailToRemoveMissingJob() { // when repository.removeIfStopped("foo"); // then // no Exception is thrown... } @Test public void shouldRemoveJob() throws Exception { JobInfo stoppedJob = builder() .setJobId("some/job/stopped") .setJobType("test") .setStarted(now(fixed(Instant.now().minusSeconds(10), systemDefault()))) .setStopped(now(fixed(Instant.now().minusSeconds(7), systemDefault()))) .setHostname("localhost") .setStatus(JobStatus.OK) .build(); repository.createOrUpdate(stoppedJob); repository.createOrUpdate(stoppedJob); repository.removeIfStopped(stoppedJob.getJobId()); assertThat(repository.size(), is(0L)); } @Test public void shouldFindAll() { // given repository.createOrUpdate(newJobInfo("oldest", "FOO", fixed(Instant.now().minusSeconds(1), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("youngest", "FOO", fixed(Instant.now(), systemDefault()), "localhost")); // when final List<JobInfo> jobInfos = repository.findAll(); // then assertThat(jobInfos.size(), is(2)); assertThat(jobInfos.get(0).getJobId(), is("youngest")); assertThat(jobInfos.get(1).getJobId(), is("oldest")); } @Test public void shouldFindLatestDistinct() throws Exception { // Given Instant now = Instant.now(); final JobInfo eins = newJobInfo("eins", "eins", fixed(now.plusSeconds(10), systemDefault()), "localhost"); final JobInfo zwei = newJobInfo("zwei", "eins", fixed(now.plusSeconds(20), systemDefault()), "localhost"); final JobInfo drei = newJobInfo("drei", "zwei", fixed(now.plusSeconds(30), systemDefault()), "localhost"); final JobInfo vier = newJobInfo("vier", "drei", fixed(now.plusSeconds(40), systemDefault()), "localhost"); final JobInfo fuenf = newJobInfo("fuenf", "drei", fixed(now.plusSeconds(50), systemDefault()), "localhost"); repository.createOrUpdate(eins); repository.createOrUpdate(zwei); repository.createOrUpdate(drei); repository.createOrUpdate(vier); repository.createOrUpdate(fuenf); // When List<JobInfo> latestDistinct = repository.findLatestJobsDistinct(); // Then assertThat(latestDistinct, hasSize(3)); assertThat(latestDistinct, Matchers.containsInAnyOrder(fuenf, zwei, drei)); } @Test public void shouldFindRunningJobsWithoutUpdatedSinceSpecificDate() throws Exception { // given repository.createOrUpdate(newJobInfo("deadJob", "FOO", fixed(Instant.now().minusSeconds(10), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("running", "FOO", fixed(Instant.now(), systemDefault()), "localhost")); // when final List<JobInfo> jobInfos = repository.findRunningWithoutUpdateSince(now().minus(5, ChronoUnit.SECONDS)); // then assertThat(jobInfos, IsCollectionWithSize.hasSize(1)); assertThat(jobInfos.get(0).getJobId(), is("deadJob")); } @Test public void shouldFindLatestByType() { // given final String type = "TEST"; final String otherType = "OTHERTEST"; repository.createOrUpdate(newJobInfo("oldest", type, fixed(Instant.now().minusSeconds(10), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("other", otherType, fixed(Instant.now().minusSeconds(5), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("youngest", type, fixed(Instant.now(), systemDefault()), "localhost")); // when final List<JobInfo> jobInfos = repository.findLatestBy(type, 2); // then assertThat(jobInfos.get(0).getJobId(), is("youngest")); assertThat(jobInfos.get(1).getJobId(), is("oldest")); assertThat(jobInfos, hasSize(2)); } @Test public void shouldFindLatest() { // given final String type = "TEST"; final String otherType = "OTHERTEST"; repository.createOrUpdate(newJobInfo("oldest", type, fixed(Instant.now().minusSeconds(10), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("other", otherType, fixed(Instant.now().minusSeconds(5), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("youngest", type, fixed(Instant.now(), systemDefault()), "localhost")); // when final List<JobInfo> jobInfos = repository.findLatest(2); // then assertThat(jobInfos.get(0).getJobId(), is("youngest")); assertThat(jobInfos.get(1).getJobId(), is("other")); assertThat(jobInfos, hasSize(2)); } @Test public void shouldFindAllJobsOfSpecificType() throws Exception { // Given final String type = "TEST"; final String otherType = "OTHERTEST"; repository.createOrUpdate(builder() .setJobId("1") .setJobType(type) .setStarted(now(fixed(Instant.now().minusSeconds(10), systemDefault()))) .setStopped(now(fixed(Instant.now().minusSeconds(7), systemDefault()))) .setHostname("localhost") .setStatus(JobStatus.OK) .build()); repository.createOrUpdate(newJobInfo("2", otherType, systemDefaultZone(), "localhost")); repository.createOrUpdate(newJobInfo("3", type, systemDefaultZone(), "localhost")); // When final List<JobInfo> jobsType1 = repository.findByType(type); final List<JobInfo> jobsType2 = repository.findByType(otherType); // Then assertThat(jobsType1.size(), is(2)); assertThat(jobsType1.stream().anyMatch(job -> job.getJobId().equals("1")), is(true)); assertThat(jobsType1.stream().anyMatch(job -> job.getJobId().equals("3")), is(true)); assertThat(jobsType2.size(), is(1)); assertThat(jobsType2.stream().anyMatch(job -> job.getJobId().equals("2")), is(true)); } @Test public void shouldFindStatusOfJob() throws Exception { //Given final String type = "TEST"; JobInfo jobInfo = newJobInfo("1", type, systemDefaultZone(), "localhost"); repository.createOrUpdate(jobInfo); //When JobStatus status = repository.findStatus("1"); //Then assertThat(status, is(JobStatus.OK)); } @Test public void shouldAppendMessageToJobInfo() throws Exception { String someUri = "someUri"; //Given JobInfo jobInfo = newJobInfo(someUri, "TEST", systemDefaultZone(), "localhost"); repository.createOrUpdate(jobInfo); //When JobMessage igelMessage = JobMessage.jobMessage(Level.WARNING, "Der Igel ist froh.", now()); repository.appendMessage(someUri, igelMessage); //Then JobInfo jobInfoFromRepo = repository.findOne(someUri).get(); assertThat(jobInfoFromRepo.getMessages().size(), is(1)); assertThat(jobInfoFromRepo.getMessages().get(0), is(igelMessage)); } @Test public void shouldUpdateJobStatus() { //Given final JobInfo foo = jobInfo("http://localhost/foo", "T_FOO"); //default jobStatus is 'OK' repository.createOrUpdate(foo); //When repository.setJobStatus(foo.getJobId(), ERROR); JobStatus status = repository.findStatus("http://localhost/foo"); //Then assertThat(status, is(ERROR)); } @Test public void shouldUpdateJobLastUpdateTime() { //Given final JobInfo foo = jobInfo("http://localhost/foo", "T_FOO"); repository.createOrUpdate(foo); OffsetDateTime myTestTime = OffsetDateTime.of(1979, 2, 5, 1, 2, 3, 4, ZoneOffset.UTC); //When repository.setLastUpdate(foo.getJobId(), myTestTime); final Optional<JobInfo> jobInfo = repository.findOne(foo.getJobId()); //Then assertThat(jobInfo.get().getLastUpdated(), is(myTestTime)); } @Test public void shouldClearJobInfos() throws Exception { //Given JobInfo stoppedJob = builder() .setJobId("some/job/stopped") .setJobType("test") .setStarted(now(fixed(Instant.now().minusSeconds(10), systemDefault()))) .setStopped(now(fixed(Instant.now().minusSeconds(7), systemDefault()))) .setHostname("localhost") .setStatus(JobStatus.OK) .build(); repository.createOrUpdate(stoppedJob); //When repository.deleteAll(); //Then assertThat(repository.findAll(), is(emptyList())); } private JobInfo jobInfo(final String jobId, final String type) { return JobInfo.newJobInfo( jobId, type, now(), now(), Optional.of(now()), OK, asList( jobMessage(Level.INFO, "foo", now()), jobMessage(Level.WARNING, "bar", now())), systemDefaultZone(), "localhost" ); } }