[BP-843] feat: added cyclic report rest interface

* added rest interface
* added testcase for rest interface and cyclic reports
  controller
* added application properties parameter for cyclic
  report generation feature

Signed-off-by: Tobias Stummer <stummer@develop-group.de>
diff --git a/oKBereitschaftsplanungBackend/src/main/java/org/eclipse/openk/sp/rest/CyclicReportsRestService.java b/oKBereitschaftsplanungBackend/src/main/java/org/eclipse/openk/sp/rest/CyclicReportsRestService.java
new file mode 100644
index 0000000..0875c48
--- /dev/null
+++ b/oKBereitschaftsplanungBackend/src/main/java/org/eclipse/openk/sp/rest/CyclicReportsRestService.java
@@ -0,0 +1,101 @@
+/* *******************************************************************************
+ * Copyright (c) 2020 Basys GmbH
+ * 
+ * See the NOTICE file(s) distributed with this work for additional 
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * *******************************************************************************/
+package org.eclipse.openk.sp.rest;
+
+import java.util.List;
+
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.log4j.Logger;
+import org.eclipse.openk.common.Globals;
+import org.eclipse.openk.resources.BaseResource;
+import org.eclipse.openk.sp.controller.CyclicReportsController;
+import org.eclipse.openk.sp.dto.ReportGenerationConfigDto;
+import org.eclipse.openk.sp.util.FileHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import io.swagger.annotations.ApiParam;
+
+@Path("auto-reports")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class CyclicReportsRestService extends BaseResource {
+
+	@Autowired
+	private CyclicReportsController automaticReportsController;
+
+	public CyclicReportsRestService() {
+		super(Logger.getLogger(CyclicReportsRestService.class.getName()), new FileHelper());
+	}
+
+	@GET
+	@Path("/")
+	public Response getAllReportGenerationConfig(
+			@ApiParam(name = "Authorization", value = "JWT Token", required = true) @HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String jwt) {
+
+		ModifyingInvokable<List<ReportGenerationConfigDto>> invokable = modusr -> automaticReportsController.getAllReportGenerationConfig();
+
+		String[] securityRoles = Globals.getAllRolls();
+
+		return invokeRunnable(jwt, securityRoles, invokable);
+	}
+
+	@PUT
+	@Path("/")
+	public Response addReportGenerationConfig(@Valid ReportGenerationConfigDto reportGenerationConfig,
+			@ApiParam(name = "Authorization", value = "JWT Token", required = true) @HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String jwt) {
+
+		ModifyingInvokable<ReportGenerationConfigDto> invokable = modusr -> automaticReportsController.addReportGenerationConfig(reportGenerationConfig);
+
+		String[] securityRoles ={Globals.KEYCLOAK_ROLE_BP_ADMIN};
+
+		return invokeRunnable(jwt, securityRoles, invokable);
+	}
+
+	@DELETE
+	@Path("/{configId}")
+	public Response deleteReportGenerationConfig(@PathParam("configId") Long configId,
+			@ApiParam(name = "Authorization", value = "JWT Token", required = true) @HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String jwt) {
+
+		ModifyingInvokable<Response> invokable = modusr -> automaticReportsController.deleteReportGenerationConfig(configId);
+
+		String[] securityRoles ={Globals.KEYCLOAK_ROLE_BP_ADMIN};
+
+		return invokeRunnable(jwt, securityRoles, invokable);
+	}
+
+	@POST
+	@Path("/{configId}")
+	public Response editReportGenerationConfig(@PathParam("configId") Long configId,
+			@Valid ReportGenerationConfigDto reportGenerationConfig,
+			@ApiParam(name = "Authorization", value = "JWT Token", required = true) @HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String jwt) {
+
+		ModifyingInvokable<ReportGenerationConfigDto> invokable = modusr -> automaticReportsController.editReportGenerationConfig(configId, reportGenerationConfig);
+
+		String[] securityRoles ={Globals.KEYCLOAK_ROLE_BP_ADMIN};
+
+		return invokeRunnable(jwt, securityRoles, invokable);
+	}
+
+}
diff --git a/oKBereitschaftsplanungBackend/src/main/resources/application.properties b/oKBereitschaftsplanungBackend/src/main/resources/application.properties
index ad3c753..0371c60 100644
--- a/oKBereitschaftsplanungBackend/src/main/resources/application.properties
+++ b/oKBereitschaftsplanungBackend/src/main/resources/application.properties
@@ -28,7 +28,7 @@
 portal.useHttps=true

 

 #Application

-backend.version=DEVELOP 0.9.0

+backend.version=DEVELOP 0.10.0

 backend.timezone=${timezone}

 frontend.dashboard.url=https://${tomcatHost}/spfe/dashboard

 

@@ -65,3 +65,15 @@
 validate.transfer=false

 validate.delete=false

 

+#cyclic report generation

+report.cyclic.datePattern=yyyyMMdd

+report.cyclic.timePattern=HHmm

+report.cyclic.weekPattern=ww

+report.cyclic.zoneName=Europe/Berlin

+report.cyclic.locale=de

+report.cyclic.archivePath=/opt/openkdg/reports

+report.cyclic.sendReportMail=true

+report.cyclic.archiveReport=true

+report.cyclic.slotDeltaMin=5

+report.cyclic.checkCron=15 0/5 * * * ?

+report.mail.propertiesPath=/opt/openkdg/mail-notification.properties

diff --git a/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/controller/CyclicReportsControllerTest.java b/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/controller/CyclicReportsControllerTest.java
new file mode 100644
index 0000000..0256394
--- /dev/null
+++ b/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/controller/CyclicReportsControllerTest.java
@@ -0,0 +1,412 @@
+package org.eclipse.openk.sp.controller;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.openk.sp.abstracts.AbstractDto;
+import org.eclipse.openk.sp.abstracts.AbstractEntity;
+import org.eclipse.openk.sp.controller.reports.ReportController;
+import org.eclipse.openk.sp.db.converter.EntityConverter;
+import org.eclipse.openk.sp.db.dao.CyclicReportGenerationConfigRepository;
+import org.eclipse.openk.sp.db.model.ReportGenerationConfig;
+import org.eclipse.openk.sp.dto.ReportGenerationConfigDto;
+import org.eclipse.openk.sp.dto.report.ReportDto;
+import org.eclipse.openk.sp.exceptions.SpException;
+import org.eclipse.openk.sp.util.ArchiveHelper;
+import org.eclipse.openk.sp.util.MailHelper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CyclicReportsControllerTest {
+	
+
+
+	@InjectMocks
+	private CyclicReportsController automaticReportsController;
+
+
+	@Mock
+	private CyclicReportGenerationConfigRepository automaticReportGenerationConfigRepository;
+
+	@Mock
+	private MailHelper mailHelper;
+
+	@Mock
+	private ArchiveHelper archiveHelper;
+
+	@Mock
+	private EntityConverter entityConverter;
+
+	@Mock
+	private ReportController reportController;
+	
+	@Before
+	public void init() {
+		ReflectionTestUtils.setField(automaticReportsController, "datePattern", "yyyy-MM-dd"); 
+		ReflectionTestUtils.setField(automaticReportsController, "timePattern", "HH-mm"); 
+		ReflectionTestUtils.setField(automaticReportsController, "weekPattern", "'KW'ww"); 
+		ReflectionTestUtils.setField(automaticReportsController, "archivePath", "/opt/openk/reports"); 
+		ReflectionTestUtils.setField(automaticReportsController, "slotDeltaMin", 5); 
+		ReflectionTestUtils.setField(automaticReportsController, "zoneName", "Europe/Berlin"); 
+		ReflectionTestUtils.setField(automaticReportsController, "locale", "de"); 
+		ReflectionTestUtils.setField(automaticReportsController, "sendReportMail", true); 
+		ReflectionTestUtils.setField(automaticReportsController, "archiveReport", true); 
+		ReflectionTestUtils.invokeMethod(automaticReportsController, "init");
+	}
+	
+	@Test
+	public void constructorTest() {
+		CyclicReportsController controller = new CyclicReportsController();
+		assertNotNull(controller);
+	}
+
+	@Test
+	public void getAllReportGenerationConfigTest() throws SpException {
+		List<ReportGenerationConfig> configs = new ArrayList<>();
+		ReportGenerationConfig config = new ReportGenerationConfig();
+		
+		configs.add(config);
+		Mockito.when(automaticReportGenerationConfigRepository.findAll()).thenReturn(configs);
+		ReportGenerationConfigDto reportGenerationConfigDto = new ReportGenerationConfigDto();
+		Mockito.when(entityConverter.convertEntityToDto((AbstractEntity) any(), (AbstractDto) any()))
+				.thenReturn((AbstractDto) reportGenerationConfigDto);
+		
+		List<ReportGenerationConfigDto> configDtos = automaticReportsController.getAllReportGenerationConfig();
+		assertNotNull(configDtos);
+		
+		assertTrue(configDtos.size() == 1);
+		ReportGenerationConfigDto configDto = configDtos.get(0);
+		assertTrue(configDto == reportGenerationConfigDto);
+
+	}
+
+	@Test
+	public void deleteReportGenerationConfigTest() throws SpException {
+		Long configId = 23L;
+		ReportGenerationConfig config = new ReportGenerationConfig();
+		Mockito.when(automaticReportGenerationConfigRepository.findById(Mockito.eq(configId))).thenReturn(Optional.of(config));
+		Response response = automaticReportsController.deleteReportGenerationConfig(configId);
+		assertEquals(204, response.getStatus());
+		Mockito.verify(automaticReportGenerationConfigRepository).delete(Mockito.eq(configId));
+	}
+
+	@Test
+	public void deleteReportGenerationConfigTestNotFound() {
+		Long configId = 23L;
+		Mockito.when(automaticReportGenerationConfigRepository.findById(Mockito.eq(configId))).thenReturn(Optional.empty());
+		try {
+			automaticReportsController.deleteReportGenerationConfig(configId);
+			fail("Should have thrown SpException");
+		} catch  (SpException e) {
+			// pass
+		}
+	}
+	
+	@Test
+	public void editReportGenerationConfigTest() throws SpException {
+		Long configId = 23L;
+		ReportGenerationConfig config = new ReportGenerationConfig();
+		config.setId(configId);
+		Mockito.when(automaticReportGenerationConfigRepository.findById(Mockito.eq(configId))).thenReturn(Optional.of(config));
+		ReportGenerationConfigDto reportGenerationConfigDto = new ReportGenerationConfigDto();
+		Mockito.when(entityConverter.convertDtoToEntity((AbstractDto) any(), (AbstractEntity) any())).thenReturn((AbstractEntity) config);
+		ReportGenerationConfigDto response = automaticReportsController.editReportGenerationConfig(configId, reportGenerationConfigDto);
+		assertEquals(configId, response.getId());
+		Mockito.verify(automaticReportGenerationConfigRepository).save(Mockito.eq(config));
+	}
+	
+	@Test
+	public void editReportGenerationConfigTestNotFound() throws SpException {
+		Long configId = 23L;
+		ReportGenerationConfigDto config = new ReportGenerationConfigDto();
+		Mockito.when(automaticReportGenerationConfigRepository.findById(Mockito.eq(configId))).thenReturn(Optional.empty());
+		try {
+			automaticReportsController.editReportGenerationConfig(configId, config);
+			fail("Should have thrown SpException");
+		} catch  (SpException e) {
+			// pass
+		}
+	}
+
+	@Test
+	public void addReportGenerationConfigTest() throws SpException {
+		Long configId = 23L;
+		ReportGenerationConfig config = new ReportGenerationConfig();
+		config.setId(configId);
+		ReportGenerationConfigDto reportGenerationConfigDto = new ReportGenerationConfigDto();
+		Mockito.when(entityConverter.convertDtoToEntity((AbstractDto) any(), (AbstractEntity) any())).thenReturn((AbstractEntity) config);
+		Mockito.when(entityConverter.convertEntityToDto((AbstractEntity) any(), (AbstractDto) any()))
+				.thenReturn((AbstractDto) reportGenerationConfigDto);
+		ReportGenerationConfigDto response = automaticReportsController.addReportGenerationConfig(reportGenerationConfigDto);
+		assertEquals(reportGenerationConfigDto, response);
+		Mockito.verify(automaticReportGenerationConfigRepository).save(Mockito.eq(config));
+	}
+	
+
+	@Test
+	public void generateReportTest() throws SpException {
+		ReportGenerationConfig reportCfg = new ReportGenerationConfig();
+		String reportName = "REPORT_NAME";
+		reportCfg.setReportName(reportName);
+		String printFormat = "print_format";
+		reportCfg.setPrintFormat(printFormat );
+		Long statusId = 23L;
+		reportCfg.setStatusId(statusId);
+		Integer validDayFromOffset = -3;
+		reportCfg.setValidFromDayOffset(validDayFromOffset);
+		Integer validDayFromHour = 2;
+		reportCfg.setValidFromHour(validDayFromHour);
+		Integer validDayFromMinute =  5;
+		reportCfg.setValidFromMinute(validDayFromMinute);
+
+		Integer validDayToOffset = 3;
+		reportCfg.setValidToDayOffset(validDayToOffset);
+		Integer validDayToHour = 3;
+		reportCfg.setValidToHour(validDayToHour);
+		Integer validDayToMinute =  10;
+		reportCfg.setValidToMinute(validDayToMinute);
+		LocalDateTime triggerDate = LocalDateTime.of(2020, 1, 10, 3, 50);
+
+		Date fromDate = Date.from(LocalDateTime.of(2020, 1, 7, 2, 5).atZone(ZoneId.of("UTC")).toInstant());
+		Date toDate = Date.from(LocalDateTime.of(2020, 1, 13, 3, 10).atZone(ZoneId.of("UTC")).toInstant());
+	
+		File file = Mockito.mock(File.class);
+		Mockito.when(reportController.generateReport(Mockito.any(ReportDto.class))).thenReturn(file);
+		File resp = automaticReportsController.generateReport(reportCfg, triggerDate);
+		assertTrue(file ==  resp);
+		ArgumentCaptor<ReportDto> reportDtoCaptor = ArgumentCaptor.forClass(ReportDto.class);
+
+		Mockito.verify(reportController).generateReport(reportDtoCaptor.capture());
+		ReportDto reportDto = reportDtoCaptor.getValue();
+		assertEquals(reportName, reportDto.getReportName());
+		assertEquals(printFormat, reportDto.getPrintFormat());
+		assertEquals(statusId, reportDto.getStatusId());
+		assertEquals(fromDate, reportDto.getValidFromDate());
+		assertEquals(toDate, reportDto.getValidToDate());
+	}
+
+	@Test
+	public void getReportGenerationConfigsTest() {
+		LocalDateTime triggerTimeGreaterEqual = LocalDateTime.of(2020, 1, 1, 1, 5);
+		LocalDateTime triggerTimeLowerEqual = LocalDateTime.of(2020, 1, 1, 1, 9);
+
+		automaticReportsController.getReportGenerationConfigs(triggerTimeGreaterEqual, triggerTimeLowerEqual);
+		Mockito.verify(automaticReportGenerationConfigRepository).findConfigs(3, 1, 5, 9);
+	}
+
+	@Test
+	public void generateAndDistributeReportsTest() throws SpException, MessagingException, IOException {
+		LocalDateTime triggerTimeGreaterEqual = LocalDateTime.of(2020, 1, 1, 1, 5);
+		LocalDateTime triggerTimeLowerEqual = LocalDateTime.of(2020, 1, 1, 1, 9);
+
+		List<ReportGenerationConfig> configs = new ArrayList<>();
+		ReportGenerationConfig config = sampleReportGenerationConfig();
+		configs.add(config);
+		Mockito.when(automaticReportGenerationConfigRepository.findConfigs(3, 1, 5, 9)).thenReturn(configs);
+	
+		File file = Mockito.mock(File.class);
+		Mockito.when(reportController.generateReport(Mockito.any(ReportDto.class))).thenReturn(file);
+
+		MimeMessage msg = Mockito.mock(MimeMessage.class);
+		Mockito.when(msg.getContent()).thenReturn(new MimeMultipart());
+		
+		Mockito.when(mailHelper.newMultipartMail()).thenReturn(msg);
+		
+		automaticReportsController.generateAndDistributeReports(triggerTimeGreaterEqual, triggerTimeLowerEqual);
+		
+		Mockito.verify(reportController).generateReport(Mockito.any(ReportDto.class));
+		Mockito.verify(mailHelper).send(Mockito.any(MimeMessage.class));
+		Mockito.verify(archiveHelper).copyFile(Mockito.any(String.class), Mockito.eq("/opt/openk/reports/" + config.getFileNamePattern() + "." + config.getPrintFormat()));
+		
+	}
+	
+	@Test
+	public void generateAndDistributeReportsTestIOException() throws SpException, MessagingException, IOException {
+		LocalDateTime triggerTimeGreaterEqual = LocalDateTime.of(2020, 1, 1, 1, 5);
+		LocalDateTime triggerTimeLowerEqual = LocalDateTime.of(2020, 1, 1, 1, 9);
+
+		List<ReportGenerationConfig> configs = new ArrayList<>();
+		ReportGenerationConfig config = sampleReportGenerationConfig();
+		configs.add(config);
+		Mockito.when(automaticReportGenerationConfigRepository.findConfigs(3, 1, 5, 9)).thenReturn(configs);
+	
+		File file = Mockito.mock(File.class);
+		Mockito.when(reportController.generateReport(Mockito.any(ReportDto.class))).thenReturn(file);
+		
+		Mockito.doThrow(new IOException()).when(archiveHelper).copyFile(Mockito.any(), Mockito.any());
+		
+		automaticReportsController.generateAndDistributeReports(triggerTimeGreaterEqual, triggerTimeLowerEqual);
+	
+	}
+	
+	@Test
+	public void generateAndDistributeReportsTestSpException() throws SpException, MessagingException, IOException {
+		LocalDateTime triggerTimeGreaterEqual = LocalDateTime.of(2020, 1, 1, 1, 5);
+		LocalDateTime triggerTimeLowerEqual = LocalDateTime.of(2020, 1, 1, 1, 9);
+
+		List<ReportGenerationConfig> configs = new ArrayList<>();
+		ReportGenerationConfig config = sampleReportGenerationConfig();
+		configs.add(config);
+		Mockito.when(automaticReportGenerationConfigRepository.findConfigs(3, 1, 5, 9)).thenReturn(configs);
+	
+		File file = Mockito.mock(File.class);
+		Mockito.when(reportController.generateReport(Mockito.any(ReportDto.class))).thenReturn(file);
+		
+		Mockito.doThrow(new SpException()).when(reportController).generateReport(Mockito.any());
+		
+		automaticReportsController.generateAndDistributeReports(triggerTimeGreaterEqual, triggerTimeLowerEqual);
+	
+	}
+
+
+
+	@Test
+	public void sendReportTest() throws MessagingException, IOException {
+
+		File reportFile = Mockito.mock(File.class);
+		String fileName = "fileName";
+		ReportGenerationConfig cfg = new ReportGenerationConfig();
+		String subject = "subject";
+		cfg.setSubject(subject);
+		String emailText = "mailText";
+		cfg.setEmailText(emailText);
+		List<String> toList = new ArrayList<>();
+		String email = "mail@test.tld";
+		toList.add(email);
+		cfg.setTo(toList);
+
+		ArgumentCaptor<MimeMessage> msgCaptor = ArgumentCaptor.forClass(MimeMessage.class);
+
+		MimeMessage msg = Mockito.mock(MimeMessage.class);
+		Mockito.when(msg.getContent()).thenReturn(new MimeMultipart());
+		Mockito.when(mailHelper.newMultipartMail()).thenReturn(msg);
+		LocalDateTime triggerTime = LocalDateTime.now();
+		automaticReportsController.sendReport(reportFile, fileName, cfg, triggerTime);
+		Mockito.verify(mailHelper).send(msgCaptor.capture());
+		MimeMessage sendMail = msgCaptor.getValue();
+		assertTrue(sendMail == msg);
+	
+	}
+	
+	@Test
+	public void sendReportTestMessagingException() throws MessagingException, IOException {
+	
+		File reportFile = Mockito.mock(File.class);
+		String fileName = "fileName";
+		ReportGenerationConfig cfg = new ReportGenerationConfig();
+		String subject = "subject";
+		cfg.setSubject(subject);
+		List<String> toList = new ArrayList<>();
+		String email = "mail@test.tld";
+		toList.add(email);
+		cfg.setTo(toList);
+
+		MimeMessage msg = Mockito.mock(MimeMessage.class);
+		Mockito.when(msg.getContent()).thenReturn(new MimeMultipart());
+		Mockito.when(mailHelper.newMultipartMail()).thenReturn(msg);
+		Mockito.doThrow(new MessagingException()).when(mailHelper).newMultipartMail();
+		LocalDateTime triggerTime = LocalDateTime.now();
+		automaticReportsController.sendReport(reportFile, fileName, cfg, triggerTime);
+		
+	}
+
+	@Test
+	public void fileNameOfCfgTest() {
+		ReportGenerationConfig cfg = new ReportGenerationConfig();
+		String printFormat = "pdf";
+		String fileNamePattern = "DDD-{Date}-{Time}-{Week}-filename";
+		cfg.setPrintFormat(printFormat);
+		cfg.setFileNamePattern(fileNamePattern);
+		LocalDateTime triggerDateTime = LocalDateTime.of(2020, 1, 1, 1, 5);
+		
+		String expected = "DDD-2020-01-01-01-05-KW01-filename.pdf";
+		
+		String fileName = automaticReportsController.fileNameOfCfg(triggerDateTime, cfg);
+		assertEquals(expected, fileName);
+	}
+
+
+	@Test
+	public void testCheckCyclicGenerationSlot() {
+		LocalDateTime now = LocalDateTime.now(ZoneId.of("Europe/Berlin"));
+		int weekDay = now.getDayOfWeek().getValue();
+		int hour = now.getHour();
+		int minute = now.getMinute();
+		
+		int minuteGE = ( minute / 5) * 5;
+		int minuteLE = minuteGE + 5 - 1;
+
+		automaticReportsController.checkCyclicGenerationSlot();
+
+		Mockito.verify(automaticReportGenerationConfigRepository).findConfigs(weekDay, hour, minuteGE, minuteLE);
+
+	}
+	private ReportGenerationConfig sampleReportGenerationConfig() {
+		ReportGenerationConfig config = new ReportGenerationConfig();
+		
+		Integer triggerHour = 1;
+		Integer triggerMinute = 1;
+		Integer triggerWeekDay = 1;
+		Integer validFromDayOffset = -1;
+		Integer validFromHour = 2;
+		Integer validFromMinute = 30;
+		Integer validToDayOffset = 1;
+		Integer validToHour = 3;
+		Integer validToMinute = 35;
+		Long standByListId = 23L;
+		Long statusId = 4L;
+		String fileNamePattern = "pattern";
+		String name = "name";
+		String printFormat = "pdf";
+		String reportName = "REPORT_NAME";
+		String subject = "subject";
+		config.setFileNamePattern(fileNamePattern);
+		config.setName(name);
+		config.setPrintFormat(printFormat);
+		config.setReportName(reportName);
+		config.setStandByListId(standByListId);
+		config.setStatusId(statusId);
+		config.setSubject(subject);
+		config.setTriggerHour(triggerHour);
+		config.setTriggerMinute(triggerMinute);
+		config.setTriggerWeekDay(triggerWeekDay);
+		config.setValidFromDayOffset(validFromDayOffset);
+		config.setValidFromHour(validFromHour);
+		config.setValidFromMinute(validFromMinute);
+		config.setValidToDayOffset(validToDayOffset);
+		config.setValidToHour(validToHour);
+		config.setValidToMinute(validToMinute);
+		List<String> to = new ArrayList<>();
+		to.add("email@test.tld");
+		config.setTo(to);
+		config.setEmailText("emailText");
+		return config;
+	}
+
+
+}
diff --git a/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/rest/CyclicReportsRestServiceTest.java b/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/rest/CyclicReportsRestServiceTest.java
new file mode 100644
index 0000000..1fdbb81
--- /dev/null
+++ b/oKBereitschaftsplanungBackend/src/test/java/org/eclipse/openk/sp/rest/CyclicReportsRestServiceTest.java
@@ -0,0 +1,79 @@
+/* *******************************************************************************
+ * Copyright (c) 2020 Basys GmbH
+ * 
+ * See the NOTICE file(s) distributed with this work for additional 
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * *******************************************************************************/
+package org.eclipse.openk.sp.rest;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.openk.sp.controller.CyclicReportsController;
+import org.eclipse.openk.sp.dto.ReportGenerationConfigDto;
+import org.eclipse.openk.sp.exceptions.SpException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CyclicReportsRestServiceTest {
+
+	@InjectMocks
+	private CyclicReportsRestService automaticReportsRestService;
+
+	@Mock
+	private CyclicReportsController automaticReportsController;
+
+	@Test
+	public void constructorTest() {
+		CyclicReportsRestService arrs = new CyclicReportsRestService();
+		assertNotNull(arrs);
+	}
+
+	@Test
+	public void getAllReportGenerationConfigTest() throws SpException {
+		String jwt = "TOKEN";
+		Mockito.when(automaticReportsController.getAllReportGenerationConfig()).thenReturn(new ArrayList<>());
+		Response response = automaticReportsRestService.getAllReportGenerationConfig(jwt);
+		assertNotNull(response);
+	}
+
+	@Test
+	public void addReportGenerationConfigTest() {
+		String jwt = "TOKEN";
+		ReportGenerationConfigDto reportGenerationConfig = new ReportGenerationConfigDto();
+		Response response = automaticReportsRestService.addReportGenerationConfig(reportGenerationConfig, jwt);
+		assertNotNull(response);
+	}
+
+	@Test
+	public void deleteReportGenerationConfigTest() {
+		String jwt = "TOKEN";
+		Long configId = 23L;
+		Response response = automaticReportsRestService.deleteReportGenerationConfig(configId, jwt);
+		assertNotNull(response);
+	}
+
+	@Test
+	public void editReportGenerationConfigTest() {
+		String jwt = "TOKEN";
+		ReportGenerationConfigDto reportGenerationConfig = new ReportGenerationConfigDto();
+		Long configId = 23L;
+		Response response = automaticReportsRestService.editReportGenerationConfig(configId, reportGenerationConfig,
+				jwt);
+		assertNotNull(response);
+	}
+}