Skip to content
Snippets Groups Projects
Commit 6f5469a6 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-6162 OZG-7060 Call grpc method ExportVorgang

parent 305087a1
No related branches found
No related tags found
No related merge requests found
Showing
with 312 additions and 84 deletions
package de.ozgcloud.alfa.export;
import java.io.OutputStream;
import org.springframework.stereotype.Service;
import de.ozgcloud.alfa.common.GrpcUtil;
import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceBlockingStub;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest;
import net.devh.boot.grpc.client.inject.GrpcClient;
@Service
......@@ -14,7 +13,8 @@ class ExportRemoteService {
@GrpcClient(GrpcUtil.FILE_MANAGER_GRPC_CLIENT)
private ExportServiceBlockingStub exportServiceStub;
public void exportVorgang(String vorgangId, OutputStream archiveOut) {
public ExportedVorgangFile exportVorgang(String vorgangId) {
var responseIterator = exportServiceStub.exportVorgang(GrpcExportVorgangRequest.newBuilder().setVorgangId(vorgangId).build());
return new StreamedExportedVorgangFile(responseIterator);
}
}
package de.ozgcloud.alfa.export;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
......@@ -13,39 +9,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import de.ozgcloud.alfa.common.GrpcUtil;
import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceBlockingStub;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse;
import net.devh.boot.grpc.client.inject.GrpcClient;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping(ExportVorgangController.PATH)
@RequiredArgsConstructor
public class ExportVorgangController {
static final String PATH = "/api/vorgangs"; // NOSONAR
private static final String EXPORT_FILENAME_TEMPLATE = "%s_Abgabe.Abgabe.0401.xdomea";
@GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT)
private ExportServiceBlockingStub grpcService;
private final ExportRemoteService exportRemoteService;
@GetMapping(value = "{vorgangId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<StreamingResponseBody> exportToXdomea(@PathVariable String vorgangId) {
var response = grpcService.exportVorgang(GrpcExportVorgangRequest.newBuilder().setVorgangId(vorgangId).build());
public ResponseEntity<StreamingResponseBody> exportVorgang(@PathVariable String vorgangId) {
var exportedVorgangFile = exportRemoteService.exportVorgang(vorgangId);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", response.next().getVorgangFile().getFileName()))
.header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", exportedVorgangFile.getFileName()))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(out -> writeResponse(response, out));
}
String buildZipFilename(String filenameId) {
return String.format(EXPORT_FILENAME_TEMPLATE, filenameId);
}
void writeResponse(Iterator<GrpcExportVorgangResponse> response, OutputStream outputStream) throws IOException {
while (response.hasNext()) {
outputStream.write(response.next().getVorgangFile().getFileContent().toByteArray());
}
.body(exportedVorgangFile::writeToOutputStream);
}
}
......@@ -33,7 +33,7 @@ class ExportVorgangProcessor implements RepresentationModelProcessor<EntityModel
return ModelBuilder.fromModel(model)
.ifMatch(IS_VORGANG_ABGESCHLOSSEN)
.addLink(linkTo(methodOn(ExportVorgangController.class).exportToXdomea(vorgang.getId())).withRel(REL_EXPORT))
.addLink(linkTo(methodOn(ExportVorgangController.class).exportVorgang(vorgang.getId())).withRel(REL_EXPORT))
.buildModel();
}
}
package de.ozgcloud.alfa.export;
import java.io.IOException;
import java.io.OutputStream;
interface ExportedVorgangFile {
String getFileName();
void writeToOutputStream(OutputStream outputStream) throws IOException;
}
package de.ozgcloud.alfa.export;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse;
import de.ozgcloud.common.errorhandling.TechnicalException;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
class StreamedExportedVorgangFile implements ExportedVorgangFile {
private final Iterator<GrpcExportVorgangResponse> responseIterator;
@Override
public String getFileName() {
if (!responseIterator.hasNext()) {
throw new TechnicalException("Response is empty");
}
return responseIterator.next().getVorgangFile().getFileName();
}
@Override
public void writeToOutputStream(OutputStream outputStream) throws IOException {
while (responseIterator.hasNext()) {
outputStream.write(responseIterator.next().getVorgangFile().getFileContent().toByteArray());
}
}
}
package de.ozgcloud.alfa.export;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Iterator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceBlockingStub;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse;
class ExportRemoteServiceTest {
@Spy
@InjectMocks
private ExportRemoteService service;
@Mock
private ExportServiceBlockingStub exportServiceStub;
@Nested
class TestExportVorgang {
public static final String VORGANG_ID = VorgangHeaderTestFactory.ID;
private static final ArgumentMatcher<GrpcExportVorgangRequest> HAS_VORGANG_ID = request -> request.getVorgangId().equals(VorgangHeaderTestFactory.ID);
@Mock
private Iterator<GrpcExportVorgangResponse> responseIterator;
@BeforeEach
void init() {
when(exportServiceStub.exportVorgang(any(GrpcExportVorgangRequest.class))).thenReturn(responseIterator);
}
@Test
void shouldExportVorgang() {
service.exportVorgang(VORGANG_ID);
verify(exportServiceStub).exportVorgang(argThat(HAS_VORGANG_ID));
}
@Test
void shouldReturnExportedVorgangFile() {
var exportedVorgangFile = service.exportVorgang(VORGANG_ID);
assertThat(exportedVorgangFile).isInstanceOf(StreamedExportedVorgangFile.class).extracting("responseIterator").isEqualTo(responseIterator);
}
}
}
package de.ozgcloud.alfa.export;
import static org.assertj.core.api.AssertionsForClassTypes.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.io.OutputStream;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
......@@ -21,7 +19,6 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import de.ozgcloud.alfa.common.AlfaTestUtils;
import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
class ExportVorgangControllerTest {
......@@ -29,6 +26,8 @@ class ExportVorgangControllerTest {
@Spy
@InjectMocks
private ExportVorgangController controller;
@Mock
private ExportRemoteService exportRemoteService;
private MockMvc mockMvc;
......@@ -38,58 +37,50 @@ class ExportVorgangControllerTest {
}
@Nested
class TestBuildZipFilename {
class TestExportVorgang {
public static final String VORGANG_ID = VorgangHeaderTestFactory.ID;
public static final String EXPORTED_VORGANG_FILENAME = UUID.randomUUID().toString();
@Mock
private ExportedVorgangFile exportedVorgangFile;
@BeforeEach
void init() {
when(exportedVorgangFile.getFileName()).thenReturn(EXPORTED_VORGANG_FILENAME);
when(exportRemoteService.exportVorgang(VORGANG_ID)).thenReturn(exportedVorgangFile);
}
@Test
void shouldExportVorgang() throws Exception {
doRequest();
verify(exportRemoteService).exportVorgang(VORGANG_ID);
}
@Test
void shouldMatchPattern() {
var filename = controller.buildZipFilename(UUID.randomUUID().toString());
void shouldHaveContentDispositonHeader() throws Exception {
doRequest().andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + EXPORTED_VORGANG_FILENAME));
}
assertThat(filename).matches(AlfaTestUtils.uuidRegexWithSuffix("_Abgabe.Abgabe.0401.xdomea"));
@Test
void shouldHaveContentTypeHeader() throws Exception {
doRequest().andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM.toString()));
}
@Test
void shouldWriteFileToOutputStream() throws Exception {
doRequest();
verify(exportedVorgangFile).writeToOutputStream(any(OutputStream.class));
}
// @Nested
// class TestExportToXdomea {
//
// private static final String VORGANG_EXPORT_FILENAME = "00000000-0000-0000-0000-000000000000_Abgabe.Abgabe.0401.xml";
//
// @Captor
// private ArgumentCaptor<String> filenameIdArgumentCaptor;
//
// @BeforeEach
// void init() {
// doReturn(VORGANG_EXPORT_FILENAME).when(controller).buildZipFilename(anyString());
// }
//
// @Test
// void shouldHaveContentDispositonHeader() throws Exception {
// doRequest().andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + VORGANG_EXPORT_FILENAME));
// }
//
// @Test
// void shouldCallXdomeaService() throws Exception {
// doRequest();
//
// verify(xDomeaService).writeExport(eq(VorgangHeaderTestFactory.ID), filenameIdArgumentCaptor.capture(), any());
// assertThat(filenameIdArgumentCaptor.getValue()).matches(AlfaTestUtils.UUID_REGEX);
// }
//
// @Test
// void shouldUseUUIDAsFilenameId() throws Exception {
// doRequest();
//
// verify(controller).buildZipFilename(filenameIdArgumentCaptor.capture());
//
// assertThat(filenameIdArgumentCaptor.getValue()).matches(AlfaTestUtils.UUID_REGEX);
//
// }
//
// private ResultActions doRequest() throws Exception {
// return mockMvc.perform(asyncDispatch(
// mockMvc.perform(get(ExportVorgangController.PATH + "/" + VorgangHeaderTestFactory.ID)
// .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE)).andReturn()))
// .andExpect(status().isOk());
// }
// }
private ResultActions doRequest() throws Exception {
return mockMvc.perform(asyncDispatch(
mockMvc.perform(get(ExportVorgangController.PATH + "/" + VorgangHeaderTestFactory.ID)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE)).andReturn()))
.andExpect(status().isOk());
}
}
}
\ No newline at end of file
package de.ozgcloud.alfa.export;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse;
import de.ozgcloud.archive.grpc.export.GrpcFile;
class GrpcExportVorgangResponseTestFactory {
public static final GrpcFile VORGANG_FILE_WITH_NAME = GrpcFileTestFactory.createWithName();
public static final GrpcFile VORGANG_FILE_WITH_CONTENT = GrpcFileTestFactory.createWithContent();
public static GrpcExportVorgangResponse createWithName() {
return createBuilder().setVorgangFile(VORGANG_FILE_WITH_NAME).build();
}
public static GrpcExportVorgangResponse createWithContent() {
return createBuilder().setVorgangFile(VORGANG_FILE_WITH_CONTENT).build();
}
public static GrpcExportVorgangResponse.Builder createBuilder() {
return GrpcExportVorgangResponse.newBuilder();
}
}
package de.ozgcloud.alfa.export;
import com.google.protobuf.ByteString;
import com.thedeanda.lorem.LoremIpsum;
import de.ozgcloud.archive.grpc.export.GrpcFile;
class GrpcFileTestFactory {
public static final String FILE_NAME = LoremIpsum.getInstance().getName();
public static final ByteString FILE_CONTENT = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(10));
public static GrpcFile createWithName() {
return createBuilder().setFileName(FILE_NAME).build();
}
public static GrpcFile createWithContent() {
return createBuilder().setFileContent(FILE_CONTENT).build();
}
public static GrpcFile.Builder createBuilder() {
return GrpcFile.newBuilder();
}
}
package de.ozgcloud.alfa.export;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import com.google.protobuf.ByteString;
import com.thedeanda.lorem.LoremIpsum;
import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse;
import de.ozgcloud.common.errorhandling.TechnicalException;
class StreamedExportedVorgangFileTest {
@Mock
private Iterator<GrpcExportVorgangResponse> responseIterator;
@InjectMocks
private StreamedExportedVorgangFile exportedVorgangFile;
@Nested
class TestGetFileName {
@Nested
class OnEmptyResponse {
@BeforeEach
void init() {
when(responseIterator.hasNext()).thenReturn(false);
}
@Test
void shouldThrowException() {
assertThatExceptionOfType(TechnicalException.class).isThrownBy(exportedVorgangFile::getFileName);
}
}
@Nested
class OnNotEmptyResponse {
@BeforeEach
void init() {
when(responseIterator.hasNext()).thenReturn(true);
when(responseIterator.next()).thenReturn(GrpcExportVorgangResponseTestFactory.createWithName());
}
@Test
void shouldCallHasNext() {
exportedVorgangFile.getFileName();
verify(responseIterator).hasNext();
}
@Test
void shouldCallNextOnce() {
exportedVorgangFile.getFileName();
verify(responseIterator, times(1)).next();
}
@Test
void shouldReturnFileName() {
var fileName = exportedVorgangFile.getFileName();
assertThat(fileName).isEqualTo(GrpcFileTestFactory.FILE_NAME);
}
}
}
@Nested
class TestWriteToOutputStream {
public static final ByteString FILE_CONTENT_1 = GrpcFileTestFactory.FILE_CONTENT;
public static final ByteString FILE_CONTENT_2 = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(8));
@Mock
private OutputStream outputStream;
@BeforeEach
void init() {
when(responseIterator.hasNext())
.thenReturn(true)
.thenReturn(true)
.thenReturn(false);
when(responseIterator.next())
.thenReturn(GrpcExportVorgangResponseTestFactory.createWithContent())
.thenReturn(GrpcExportVorgangResponseTestFactory.createBuilder().setVorgangFile(
GrpcFileTestFactory.createBuilder().setFileContent(FILE_CONTENT_2).build()
).build());
}
@Test
void shouldWriteFileContentInOrder() throws IOException {
var orderVerifier = inOrder(outputStream);
exportedVorgangFile.writeToOutputStream(outputStream);
orderVerifier.verify(outputStream).write(FILE_CONTENT_1.toByteArray());
orderVerifier.verify(outputStream).write(FILE_CONTENT_2.toByteArray());
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment