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

OZG-6514 Anbindung Collaboration Manager

parent ec86bbff
No related branches found
No related tags found
No related merge requests found
Showing
with 579 additions and 98 deletions
......@@ -3,6 +3,8 @@ config_version: 3
http:
rules:
- selector: de.ozgcloud.zufi.grpc.fachstelle.FachstelleRegistrationService.Register
- selector: de.ozgcloud.fachstellenproxy.FachstelleRegistrationService.Register
post: /api/fachstellen
body: "*"
- selector: de.ozgcloud.fachstellenproxy.CollaborationService.FindVorgang
get: /api/vorgang/{vorgangId}/{samlToken}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.fachstellenproxy;
option go_package = "de.ozgcloud.fachstellenproxy";
message GrpcClientAttribute {
string clientName = 1;
string attributeName = 2;
GrpcAccessPermission access = 3;
GrpcClientAttributeValue value = 4;
}
enum GrpcAccessPermission {
PRIVATE = 0;
READ_ONLY = 1;
READ_WRITE = 2;
}
message GrpcClientAttributeValue {
oneof value {
string stringValue = 1;
int64 intValue = 2;
double doubleValue = 3;
bool boolValue = 4;
}
}
\ No newline at end of file
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.fachstellenproxy;
import "vorgang.model.proto";
option go_package = "de.ozgcloud.fachstellenproxy";
message GrpcFindVorgangRequest {
string vorgangId = 1;
string samlToken = 2;
}
message GrpcFindVorgangResponse {
repeated GrpcVorgangWithEingang vorgang = 1;
}
\ No newline at end of file
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.fachstellenproxy;
import "collaboration.model.proto";
option go_package = "de.ozgcloud.fachstellenproxy";
service CollaborationService {
rpc FindVorgang(GrpcFindVorgangRequest) returns (GrpcFindVorgangResponse);
}
\ No newline at end of file
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.fachstellenproxy;
option go_package = "de.ozgcloud.fachstellenproxy";
message GrpcObject {
repeated GrpcProperty property = 1;
repeated GrpcSubObject subObject = 2;
}
message GrpcProperty {
string name = 1;
repeated string value = 2;
}
message GrpcSubObject {
string name = 1;
repeated GrpcProperty property = 2;
repeated GrpcSubObject subObject = 3;
}
\ No newline at end of file
......@@ -25,9 +25,9 @@
syntax = "proto3";
package de.ozgcloud.zufi.grpc.fachstelle;
package de.ozgcloud.fachstellenproxy;
option go_package = "de.ozgcloud.zufi.grpc.fachstelle";
option go_package = "de.ozgcloud.fachstellenproxy";
message GrpcFachstelleRegistrationRequest {
GrpcFachstelle fachstelle = 1;
......
......@@ -25,11 +25,11 @@
syntax = "proto3";
package de.ozgcloud.zufi.grpc.fachstelle;
package de.ozgcloud.fachstellenproxy;
import "fachstelleregistration.model.proto";
option go_package = "de.ozgcloud.zufi.grpc.fachstelle";
option go_package = "de.ozgcloud.fachstellenproxy";
service FachstelleRegistrationService {
rpc Register(GrpcFachstelleRegistrationRequest) returns (GrpcFachstelleRegistrationResponse);
......
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.fachstellenproxy;
import "clientattribute.model.proto";
import "common.model.proto";
option go_package = "de.ozgcloud.fachstellenproxy";
message GrpcVorgangWithEingang {
string id = 1;
int64 version = 2;
string status = 3;
string name = 4;
string createdAt = 5;
string aktenzeichen = 6;
string assignedTo = 7;
string nummer = 8;
repeated GrpcClientAttribute clientAttributes = 9;
GrpcEingang eingang = 10;
string formEngineName = 15;
GrpcVorgangHead header = 16;
}
message GrpcVorgangHead {
GrpcServiceKonto serviceKonto = 1;
}
message GrpcEingang {
string id = 1;
GrpcEingangHeader header = 2;
GrpcAntragsteller antragsteller = 3;
GrpcZustaendigeStelle zustaendigeStelle = 4;
GrpcFormData formData = 10;
int32 numberOfAttachments = 11;
int32 numberOfRepresentations = 12;
repeated GrpcIncomingFileGroup attachments = 20;
repeated GrpcIncomingFile representations = 21;
}
message GrpcIncomingFileGroup {
string name = 1;
repeated GrpcIncomingFile files = 2;
}
message GrpcIncomingFile {
string id = 1;
string vendorId = 2;
string name = 3;
string contentType = 4;
int64 size = 5;
bytes content = 6;
}
message GrpcEingangHeader {
string requestId = 1;
string createdAt = 2;
string formId = 3;
string formName = 4;
string sender = 5;
string customer = 6 [deprecated = true];
string customerId = 7 [deprecated = true];
string client = 8 [deprecated = true];
string clientId = 9 [deprecated = true];
string formEngineName = 10;
GrpcServiceKonto serviceKonto = 11;
string vorgangNummer = 12;
}
message GrpcServiceKonto {
string type = 1;
repeated GrpcPostfachAddress postfachAddresses = 2;
string trustLevel = 3;
}
message GrpcPostfachAddress {
string version = 1;
GrpcObject identifier = 2;
int32 type = 3;
}
message GrpcAntragsteller {
string anrede = 1;
string nachname = 2;
string vorname = 3;
string geburtsdatum = 4;
string geburtsort = 5;
string geburtsname = 6;
string email = 7;
string telefon = 8;
string strasse = 9;
string hausnummer = 10;
string plz = 11;
string ort = 12;
string postfachId = 13 [deprecated = true];
GrpcFormData otherData = 30;
string firmaName = 31;
}
message GrpcFormData {
repeated GrpcFormField field = 1;
repeated GrpcSubForm form = 2;
}
message GrpcFormField {
string name = 1;
string value = 2;
string label = 3;
}
message GrpcSubForm {
string title = 1;
repeated GrpcFormField field = 2;
repeated GrpcSubForm subForm = 3;
string label = 4;
GrpcControlData controlData = 5;
}
message GrpcControlData {
bool metadata = 1;
}
message GrpcZustaendigeStelle {
string organisationseinheitenId = 1;
string email = 2;
string bezeichnung = 3;
string gemeindeSchluessel = 4;
string amtlicherRegionalSchluessel = 5;
string hausanschriftStrasse = 6;
string hausanschriftPlz = 7;
string hausanschriftOrt = 8;
string telefon = 9;
}
\ No newline at end of file
......@@ -26,6 +26,7 @@
package config
import (
"fmt"
"github.com/kelseyhightower/envconfig"
"gopkg.in/yaml.v3"
"log"
......@@ -38,6 +39,7 @@ const (
defaultFilePath = "config/config.yml"
testFilePath = "testdata/test_config.yml"
grpcUrlRegex = `^[A-Za-z\d-]+(\.[A-Za-z\d-]+){0,512}:\d{1,5}$`
GrpcMockPort = 50051
)
type Config struct {
......@@ -46,7 +48,8 @@ type Config struct {
} `yaml:"server"`
Grpc struct {
Mock bool `yaml:"mock" envconfig:"GRPC_MOCK"`
Url string `yaml:"url" envconfig:"GRPC_URL"`
FachstelleRegistrationUrl string `yaml:"fachstelleRegistrationUrl" envconfig:"GRPC_FACHSTELLE_REGISTRATION_URL"`
CollaborationUrl string `yaml:"collaborationUrl" envconfig:"GRPC_COLLABORATION_URL"`
} `yaml:"grpc"`
Logging struct {
Level string `yaml:"level" envconfig:"LOGGING_LEVEL"`
......@@ -78,8 +81,19 @@ func LoadConfig(configFilePath ...string) Config {
log.Fatalf("FATAL: error reading env: %v", err)
}
if len(config.Grpc.Url) > 0 && !ValidateGrpcUrl(config.Grpc.Url) {
log.Fatalf("FATAL: gRPC URL is not in host:port format")
if config.Grpc.Mock {
config.Grpc.FachstelleRegistrationUrl = fmt.Sprintf("localhost:%d", GrpcMockPort)
config.Grpc.CollaborationUrl = fmt.Sprintf("localhost:%d", GrpcMockPort)
return config
}
if !ValidateGrpcUrl(config.Grpc.FachstelleRegistrationUrl) {
log.Fatalf("FATAL: gRPC Fachstelle Registration URL is not in host:port format")
}
if !ValidateGrpcUrl(config.Grpc.CollaborationUrl) {
log.Fatalf("FATAL: gRPC Collaboration URL is not in host:port format")
}
return config
......
......@@ -38,7 +38,8 @@ func TestLoadConfig(t *testing.T) {
expectedConfig := Config{}
expectedConfig.Server.Port = 8080
expectedConfig.Grpc.Url = "localhost:50051"
expectedConfig.Grpc.FachstelleRegistrationUrl = "localhost:50051"
expectedConfig.Grpc.CollaborationUrl = "localhost:50052"
expectedConfig.Grpc.Mock = false
expectedConfig.Logging.Level = "DEBUG"
......@@ -48,7 +49,8 @@ func TestLoadConfig(t *testing.T) {
t.Run("should load config from env", func(t *testing.T) {
envVars := map[string]string{
"SERVER_PORT": "9090",
"GRPC_URL": "localhost:99999",
"GRPC_FACHSTELLE_REGISTRATION_URL": "localhost:99999",
"GRPC_COLLABORATION_URL": "localhost:88888",
"LOGGING_LEVEL": "ERROR",
}
......@@ -64,7 +66,8 @@ func TestLoadConfig(t *testing.T) {
expectedConfig := Config{}
expectedConfig.Server.Port = 9090
expectedConfig.Grpc.Url = "localhost:99999"
expectedConfig.Grpc.FachstelleRegistrationUrl = "localhost:99999"
expectedConfig.Grpc.CollaborationUrl = "localhost:88888"
expectedConfig.Grpc.Mock = false
expectedConfig.Logging.Level = "ERROR"
......@@ -72,16 +75,26 @@ func TestLoadConfig(t *testing.T) {
})
t.Run("should overwrite config with env", func(t *testing.T) {
assert.NoError(t, os.Setenv("SERVER_PORT", "9090"), "Setenv SERVER_PORT should not return an error")
envVars := map[string]string{
"SERVER_PORT": "9090",
"GRPC_MOCK": "true",
}
for key, value := range envVars {
assert.NoError(t, os.Setenv(key, value), "Setenv "+key+" should not return an error")
}
config := LoadConfig()
assert.NoError(t, os.Unsetenv("SERVER_PORT"), "Unsetenv SERVER_PORT should not return an error")
for key := range envVars {
assert.NoError(t, os.Unsetenv(key), "Unsetenv "+key+" should not return an error")
}
expectedConfig := Config{}
expectedConfig.Server.Port = 9090
expectedConfig.Grpc.Url = "localhost:50051"
expectedConfig.Grpc.Mock = false
expectedConfig.Grpc.FachstelleRegistrationUrl = "localhost:50051"
expectedConfig.Grpc.CollaborationUrl = "localhost:50051"
expectedConfig.Grpc.Mock = true
expectedConfig.Logging.Level = "DEBUG"
assert.Equal(t, expectedConfig, config)
......
server:
port: 8080
grpc:
url: "localhost:50051"
fachstelleRegistrationUrl: "localhost:50051"
collaborationUrl: "localhost:50052"
logging:
level: "DEBUG"
\ No newline at end of file
server:
port: 8080
grpc:
url: "localhost:50051"
fachstelleRegistrationUrl: "localhost:50051"
collaborationUrl: "localhost:50052"
logging:
level: "INFO"
\ No newline at end of file
......@@ -28,6 +28,7 @@ package mock
import (
"context"
pb "fachstellen-proxy/gen/go"
"fachstellen-proxy/internal/config"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
......@@ -35,38 +36,53 @@ import (
"net"
)
const GrpcMockPort = 50051
type server struct {
type fachstelleRegistrationServer struct {
pb.UnimplementedFachstelleRegistrationServiceServer
}
func (s *server) Register(ctx context.Context, in *pb.GrpcFachstelleRegistrationRequest) (*pb.GrpcFachstelleRegistrationResponse, error) {
func (s *fachstelleRegistrationServer) Register(ctx context.Context, in *pb.GrpcFachstelleRegistrationRequest) (*pb.GrpcFachstelleRegistrationResponse, error) {
if in.Fachstelle == nil {
return nil, status.Error(codes.InvalidArgument, "Fachstelle is missing")
}
if in.Fachstelle.MukId == "conflictMukId" {
return nil, status.Error(codes.AlreadyExists, "Conflict mukId")
return nil, status.Error(codes.AlreadyExists, "Conflict MukId")
} else if in.Fachstelle.MukId == "unavailableMukId" {
return nil, status.Error(codes.Unavailable, "Unavailable mukId")
return nil, status.Error(codes.Unavailable, "Unavailable MukId")
} else if in.Fachstelle.MukId == "erroneousMukId" {
return nil, status.Error(codes.Internal, "Erroneous mukId")
return nil, status.Error(codes.Internal, "Erroneous MukId")
}
return &pb.GrpcFachstelleRegistrationResponse{}, nil
}
type collaborationServer struct {
pb.UnimplementedCollaborationServiceServer
}
func (s *collaborationServer) FindVorgang(ctx context.Context, in *pb.GrpcFindVorgangRequest) (*pb.GrpcFindVorgangResponse, error) {
if in.VorgangId == "" {
return nil, status.Error(codes.InvalidArgument, "VorgangId is missing")
}
if in.SamlToken == "" {
return nil, status.Error(codes.InvalidArgument, "SamlToken is missing")
}
return &pb.GrpcFindVorgangResponse{}, nil
}
func StartGrpcServer() *grpc.Server {
s := grpc.NewServer()
pb.RegisterFachstelleRegistrationServiceServer(s, &server{})
pb.RegisterFachstelleRegistrationServiceServer(s, &fachstelleRegistrationServer{})
pb.RegisterCollaborationServiceServer(s, &collaborationServer{})
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", GrpcMockPort))
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", config.GrpcMockPort))
if err != nil {
logger.Fatal("gRPC server failed to listen: %v", err)
}
logger.Info("gRPC server listening on port %v", GrpcMockPort)
logger.Info("gRPC server listening on port %v", config.GrpcMockPort)
if err := s.Serve(lis); err != nil {
logger.Fatal("gRPC server failed to serve: %v", err)
}
......
......@@ -26,20 +26,40 @@
package mock
import (
"bytes"
"context"
pb "fachstellen-proxy/gen/go"
"fachstellen-proxy/internal/config"
"fmt"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
"testing"
)
func TestStartGrpcServer(t *testing.T) {
t.Run("should log gRPC server start", func(t *testing.T) {
var buf bytes.Buffer
logger.BaseLogger.SetOutput(&buf)
originalFlags := log.Flags()
defer func() {
log.SetOutput(nil)
log.SetFlags(originalFlags)
}()
SetUpGrpcServer()
logOutput := buf.String()
assert.Contains(t, logOutput, "gRPC server listening on port 50051")
})
t.Run("TestFachstelleRegistrationEndpoint", func(t *testing.T) {
setUpGrpcEnv := func() (pb.FachstelleRegistrationServiceClient, func()) {
SetUpGrpcServer()
conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", GrpcMockPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", config.GrpcMockPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.NoError(t, err)
cleanup := func() {
......@@ -69,4 +89,41 @@ func TestStartGrpcServer(t *testing.T) {
assert.Error(t, err)
assert.Nil(t, resp)
})
})
t.Run("TestCollaborationEndpoint", func(t *testing.T) {
setUpGrpcEnv := func() (pb.CollaborationServiceClient, func()) {
SetUpGrpcServer()
conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", config.GrpcMockPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.NoError(t, err)
cleanup := func() {
conn.Close()
}
client := pb.NewCollaborationServiceClient(conn)
return client, cleanup
}
t.Run("should have no error", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.FindVorgang(context.Background(), &pb.GrpcFindVorgangRequest{VorgangId: "testVorgangId", SamlToken: "testSamlToken"})
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("should have error", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.FindVorgang(context.Background(), &pb.GrpcFindVorgangRequest{})
assert.Error(t, err)
assert.Nil(t, resp)
})
})
}
server:
port: 8080
grpc:
url: "localhost:50051"
fachstelleRegistrationUrl: "localhost:50051"
collaborationUrl: "localhost:50052"
logging:
level: "DEBUG"
\ No newline at end of file
......@@ -27,9 +27,12 @@ package server
import (
"context"
pb "fachstellen-proxy/gen/go"
"fmt"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"net/http"
)
......@@ -49,6 +52,22 @@ func RegisterHomeEndpoint(mux *runtime.ServeMux) {
}
}
func RegisterFachstelleRegistrationEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUrl string) {
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := pb.RegisterFachstelleRegistrationServiceHandlerFromEndpoint(ctx, mux, grpcUrl, opts)
if err != nil {
logger.Fatal("failed to register fachstelle registration endpoints: %v", err)
}
}
func RegisterCollaborationEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUrl string) {
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := pb.RegisterCollaborationServiceHandlerFromEndpoint(ctx, mux, grpcUrl, opts)
if err != nil {
logger.Fatal("failed to register collaboration endpoints: %v", err)
}
}
func ErrorHandler(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, err error) {
st, ok := status.FromError(err)
if !ok {
......
......@@ -43,12 +43,33 @@ func TestRegisterHomeEndpoint(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestRegisterFachstelleRegistrationEndpoints(t *testing.T) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
jsonData := []byte(`{"fachstelle": {"mukId": "testMukId"}}`)
resp, err := http.Post(fmt.Sprintf("http://localhost:8080%v", FachstelleRegistrationUrlPath), "application/json", bytes.NewBuffer(jsonData))
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestRegisterCollaborationEndpoints(t *testing.T) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
resp, err := http.Get(fmt.Sprintf("http://localhost:8080%v/testVorgangId/testSamlToken", VorgangUrlBasePath))
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestErrorHandler(t *testing.T) {
assertErroneousRequest := func(jsonData []byte, expectedStatusCode int) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
resp, err := http.Post(fmt.Sprintf("http://localhost:8080%v", RegisterFachstelleUrlPath), "application/json", bytes.NewBuffer(jsonData))
resp, err := http.Post(fmt.Sprintf("http://localhost:8080%v", FachstelleRegistrationUrlPath), "application/json", bytes.NewBuffer(jsonData))
assert.NoError(t, err)
assert.Equal(t, expectedStatusCode, resp.StatusCode)
......
......@@ -28,15 +28,9 @@ package server
import (
"context"
"fachstellen-proxy/internal/config"
"fachstellen-proxy/internal/mock"
"fmt"
"google.golang.org/grpc/credentials/insecure"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
pb "fachstellen-proxy/gen/go"
"net/http"
)
func StartHttpGateway(conf config.Config) *http.Server {
......@@ -44,19 +38,11 @@ func StartHttpGateway(conf config.Config) *http.Server {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
grpcEndpoint := conf.Grpc.Url
if conf.Grpc.Mock {
grpcEndpoint = fmt.Sprintf("localhost:%d", mock.GrpcMockPort)
}
mux := runtime.NewServeMux(runtime.WithErrorHandler(ErrorHandler))
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := pb.RegisterFachstelleRegistrationServiceHandlerFromEndpoint(ctx, mux, grpcEndpoint, opts)
if err != nil {
logger.Fatal("failed to start HTTP gateway: %v", err)
}
RegisterHomeEndpoint(mux)
RegisterFachstelleRegistrationEndpoints(ctx, mux, conf.Grpc.FachstelleRegistrationUrl)
RegisterCollaborationEndpoints(ctx, mux, conf.Grpc.CollaborationUrl)
httpServer := &http.Server{
Addr: fmt.Sprintf(":%d", conf.Server.Port),
......
......@@ -27,20 +27,23 @@ package server
import (
"bytes"
"fachstellen-proxy/internal/mock"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"log"
"testing"
)
func TestStartHttpGateway(t *testing.T) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
var buf bytes.Buffer
logger.BaseLogger.SetOutput(&buf)
originalFlags := log.Flags()
defer func() {
log.SetOutput(nil)
log.SetFlags(originalFlags)
}()
jsonData := []byte(`{"fachstelle": {"mukId": "testMukId"}}`)
resp, err := http.Post(fmt.Sprintf("http://localhost:8080%v", RegisterFachstelleUrlPath), "application/json", bytes.NewBuffer(jsonData))
SetUpHttpGateway()
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
logOutput := buf.String()
assert.Contains(t, logOutput, "HTTP gateway listening on port 8080")
}
......@@ -30,9 +30,13 @@ import (
"fmt"
"io"
"net/http"
"strings"
)
const RegisterFachstelleUrlPath = "/api/fachstellen"
const (
FachstelleRegistrationUrlPath = "/api/fachstellen"
VorgangUrlBasePath = "/api/vorgang"
)
type logResponseWriter struct {
http.ResponseWriter
......@@ -46,28 +50,37 @@ func (rsp *logResponseWriter) WriteHeader(statusCode int) {
func RequestLoggingMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != RegisterFachstelleUrlPath {
h.ServeHTTP(w, r)
return
}
if isRequestToBeLogged(r.URL.Path) {
body, err := io.ReadAll(r.Body)
if err != nil {
logger.Error("failed to read request body: %v", err)
logger.Error("failed to read %v request body for %v: %v", r.Method, r.URL.Path, err)
http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest)
return
}
r.Body = io.NopCloser(bytes.NewReader(body))
logger.Debug("received request with body: %v", string(body))
logger.Debug("received %v request for %v with body: %v", r.Method, r.URL.Path, string(body))
lw := &logResponseWriter{w, http.StatusOK}
h.ServeHTTP(lw, r)
if lw.statusCode == http.StatusOK {
logger.Debug("successfully handled request with body: %v", string(body))
logger.Debug("successfully handled %v request for %v with body: %v", r.Method, r.URL.Path, string(body))
} else {
logger.Error("failed handling request with body: %v, status code: %d", string(body), lw.statusCode)
logger.Error("failed handling %v request for %v with body: %v, status code: %d", r.Method, r.URL.Path, string(body), lw.statusCode)
}
}
})
}
func isRequestToBeLogged(path string) bool {
requestPathsToBeLogged := []string{FachstelleRegistrationUrlPath, VorgangUrlBasePath}
for _, rp := range requestPathsToBeLogged {
if strings.Contains(path, rp) {
return true
}
}
return false
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment