Skip to content

Commit

Permalink
Update the event-type cleanup logic
Browse files Browse the repository at this point in the history
  • Loading branch information
marcobebway committed Mar 30, 2021
1 parent 0ab5482 commit 5b30ba9
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 174 deletions.
17 changes: 16 additions & 1 deletion components/event-publisher-proxy/pkg/legacy-events/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package legacy

import (
"encoding/json"
"fmt"
"net/http"
"regexp"
"strings"
"time"

cev2event "github.com/cloudevents/sdk-go/v2/event"
Expand Down Expand Up @@ -168,10 +170,23 @@ func (t Transformer) convertPublishRequestToCloudEvent(appName string, publishRe
event.SetID(uuid.New().String())
}

eventType := formatEventType4BEB(t.eventTypePrefix, appName, publishRequest.PublishrequestV1.EventType, publishRequest.PublishrequestV1.EventTypeVersion)
eventTypeCombined := combineEventTypeSegments(publishRequest.PublishrequestV1.EventType)
eventType := formatEventType4BEB(t.eventTypePrefix, appName, eventTypeCombined, publishRequest.PublishrequestV1.EventTypeVersion)
event.SetSource(t.bebNamespace)
event.SetType(eventType)
event.SetExtension(eventTypeVersionExtensionKey, publishRequest.PublishrequestV1.EventTypeVersion)
event.SetDataContentType(ContentTypeApplicationJSON)
return &event, nil
}

// combineEventTypeSegments returns an event-type with exactly two segments separated by "." if the given event-type
// has more than two segments separated by "." (e.g. "Account.Order.Created" becomes "AccountOrder.Created")
func combineEventTypeSegments(eventType string) string {
parts := strings.Split(eventType, ".")
if len(parts) > 2 {
businessObject := strings.Join(parts[0:len(parts)-1], "")
operation := parts[len(parts)-1]
eventType = fmt.Sprintf("%s.%s", businessObject, operation)
}
return eventType
}
37 changes: 34 additions & 3 deletions components/event-publisher-proxy/pkg/legacy-events/legacy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@ import (
. "github.com/kyma-project/kyma/components/event-publisher-proxy/testing"
)

const (
eventTypeMultiSegment = "Segment1.Segment2.Segment3.Segment4.Segment5"
eventTypeMultiSegmentCombined = "Segment1Segment2Segment3Segment4.Segment5"
)

func TestConvertPublishRequestToCloudEvent(t *testing.T) {
bebNs := MessagingNamespace
eventTypePrefix := MessagingEventTypePrefix
legacyTransformer := NewTransformer(bebNs, eventTypePrefix, nil)
eventID := EventID
appName := ApplicationName
legacyEventType := LegacyEventType
legacyEventVersion := LegacyEventTypeVersion
data := LegacyEventData
timeNow := time.Now()
expectedEventType := formatEventType4BEB(eventTypePrefix, appName, legacyEventType, legacyEventVersion)
expectedEventType := formatEventType4BEB(eventTypePrefix, appName, eventTypeMultiSegmentCombined, legacyEventVersion)
timeNowStr := timeNow.Format(time.RFC3339)
timeNowFormatted, _ := time.Parse(time.RFC3339, timeNowStr)
publishReqParams := &legacyapi.PublishEventParametersV1{
PublishrequestV1: legacyapi.PublishRequestV1{
EventID: eventID,
EventType: legacyEventType,
EventType: eventTypeMultiSegment,
EventTime: timeNowStr,
EventTypeVersion: legacyEventVersion,
Data: data,
Expand Down Expand Up @@ -63,3 +67,30 @@ func TestConvertPublishRequestToCloudEvent(t *testing.T) {
t.Errorf("incorrect eventtype extension, want: %s, got: %s", legacyEventVersion, gotExtension)
}
}

func TestCombineEventTypeSegments(t *testing.T) {
testCases := []struct {
name string
givenEventType string
wantEventType string
}{
{
name: "event-type with two segments",
givenEventType: LegacyEventType,
wantEventType: LegacyEventType,
},
{
name: "event-type with more than two segments",
givenEventType: eventTypeMultiSegment,
wantEventType: eventTypeMultiSegmentCombined,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if gotEventType := combineEventTypeSegments(tc.givenEventType); tc.wantEventType != gotEventType {
t.Fatalf("invalid event-type want: %s, got: %s", tc.wantEventType, gotEventType)
}
})
}
}
5 changes: 0 additions & 5 deletions components/eventing-controller/pkg/application/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,3 @@ func GetCleanTypeOrName(application *applicationv1alpha1.Application) string {
func GetCleanName(name string) string {
return invalidApplicationNameSegment.ReplaceAllString(name, "")
}

// IsCleanName returns true if the name contains alphanumeric characters only, otherwise returns false
func IsCleanName(name string) bool {
return !invalidApplicationNameSegment.MatchString(name)
}
20 changes: 0 additions & 20 deletions components/eventing-controller/pkg/application/clean_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,3 @@ func TestCleanName(t *testing.T) {
}
}
}

func TestIsCleanName(t *testing.T) {
testCases := []struct {
givenName string
wantClean bool
}{
{givenName: "with.dot", wantClean: false},
{givenName: "with-dash", wantClean: false},
{givenName: "with_underscore", wantClean: false},
{givenName: "with#special$characters", wantClean: false},
{givenName: "alphabetical", wantClean: true},
{givenName: "alphanumeric0123", wantClean: true},
}

for _, tc := range testCases {
if gotClean := IsCleanName(tc.givenName); tc.wantClean != gotClean {
t.Errorf("Is clean application name:[%s] failed, want:[%v] but got:[%v]", tc.givenName, tc.wantClean, gotClean)
}
}
}
32 changes: 22 additions & 10 deletions components/eventing-controller/pkg/handlers/eventtype/clean.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package eventtype

import (
"regexp"

"github.com/go-logr/logr"
"github.com/kyma-project/kyma/components/eventing-controller/pkg/application"
)

var (
// invalidEventTypeSegment used to match and replace none-alphanumeric characters in the event-type segments
// as per SAP Event spec https://github.tools.sap/CentralEngineering/sap-event-specification#type
invalidEventTypeSegment = regexp.MustCompile("[^a-zA-Z0-9.]")
)

type Cleaner interface {
Clean(eventType string) (string, error)
}
Expand All @@ -22,23 +30,27 @@ func NewCleaner(eventTypePrefix string, applicationLister *application.Lister, l
return &cleaner{eventTypePrefix: eventTypePrefix, applicationLister: applicationLister, logger: logger}
}

// Clean cleans the application name segment in the event-type from none-alphanumeric characters
// and returns the clean event-type, or returns an error if the event-type parsing failed
// Clean cleans the event-type from none-alphanumeric characters and returns it
// or returns an error if the event-type parsing failed
func (c cleaner) Clean(eventType string) (string, error) {
appName, event, version, err := parse(eventType, c.eventTypePrefix)
if err != nil {
c.logger.Error(err, "failed to parse event-type", "prefix", c.eventTypePrefix, "type", eventType)
return "", err
}

// handle existing applications
if appObj, err := c.applicationLister.Get(appName); err == nil {
eventType = build(c.eventTypePrefix, application.GetCleanTypeOrName(appObj), event, version)
return eventType, nil
// clean the application name
eventTypeClean := eventType
if appObj, err := c.applicationLister.Get(appName); err != nil {
c.logger.Info("cannot find application", "name", appName)
eventTypeClean = build(c.eventTypePrefix, application.GetCleanName(appName), event, version)
} else {
eventTypeClean = build(c.eventTypePrefix, application.GetCleanTypeOrName(appObj), event, version)
}

// handle non-existing applications
c.logger.Info("failed to get application", "name", appName)
eventType = build(c.eventTypePrefix, application.GetCleanName(appName), event, version)
return eventType, nil
// clean the event-type segments
eventTypeClean = invalidEventTypeSegment.ReplaceAllString(eventTypeClean, "")
c.logger.Info("clean event-type", "before", eventType, "after", eventTypeClean)

return eventTypeClean, nil
}
139 changes: 86 additions & 53 deletions components/eventing-controller/pkg/handlers/eventtype/clean_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,115 +26,148 @@ func TestCleaner(t *testing.T) {
name: "success if the given application name is clean",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sap.kyma.testapp.order.created.v1",
wantEventType: "sap.kyma.testapp.order.created.v1",
givenEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantError: false,
},
{
name: "success if the given application name is clean and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sap.kyma.testapp.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapp.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
{
name: "success if the given application type label is clean",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenApplicationLabels: map[string]string{application.TypeLabel: "testapptype"},
givenEventType: "sap.kyma.testapp.order.created.v1",
wantEventType: "sap.kyma.testapptype.order.created.v1",
givenEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapptype.Segment1.Segment2.v1",
wantError: false,
},
{
name: "success if the given application type label is clean and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenApplicationLabels: map[string]string{application.TypeLabel: "testapptype"},
givenEventType: "sap.kyma.testapp.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapptype.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
{
name: "success if the given application name needs to be cleaned",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "t..e--s__t!!a@@p##p%%",
givenEventType: "sap.kyma.t..e--s__t!!a@@p##p%%.order.created.v1",
wantEventType: "sap.kyma.testapp.order.created.v1",
givenApplicationName: "te--s__t!!a@@p##p%%",
givenEventType: "sap.kyma.te--s__t!!a@@p##p%%.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantError: false,
},
{
name: "success if the given application name needs to be cleaned and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "te--s__t!!a@@p##p%%",
givenEventType: "sap.kyma.te--s__t!!a@@p##p%%.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapp.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
{
name: "success if the given application type label needs to be cleaned",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "t..e--s__t!!a@@p##p%%",
givenApplicationName: "te--s__t!!a@@p##p%%",
givenApplicationLabels: map[string]string{application.TypeLabel: "t..e--s__t!!a@@p##p%%t^^y&&p**e"},
givenEventType: "sap.kyma.t..e--s__t!!a@@p##p%%.order.created.v1",
wantEventType: "sap.kyma.testapptype.order.created.v1",
givenEventType: "sap.kyma.te--s__t!!a@@p##p%%.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapptype.Segment1.Segment2.v1",
wantError: false,
},
{
name: "success if the given application type label needs to be cleaned and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "te--s__t!!a@@p##p%%",
givenApplicationLabels: map[string]string{application.TypeLabel: "t..e--s__t!!a@@p##p%%t^^y&&p**e"},
givenEventType: "sap.kyma.te--s__t!!a@@p##p%%.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapptype.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
// valid even-types for non-existing applications
{
name: "success if the given application name is empty",
name: "success if the given application name is clean for non-existing application",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "",
givenEventType: "sap.kyma.test-app.order.created.v1",
wantEventType: "sap.kyma.testapp.order.created.v1",
givenEventType: "sap.kyma.test-app.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantError: false,
},
{
name: "success if the given application name is clean for non-existing application",
name: "success if the given application name is clean for non-existing application and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sap.kyma.test-app.order.created.v1",
wantEventType: "sap.kyma.testapp.order.created.v1",
givenApplicationName: "",
givenEventType: "sap.kyma.test-app.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapp.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
{
name: "success if the given application name is not clean for non-existing application",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "test-app",
givenEventType: "sap.kyma.testapp.order.created.v1",
wantEventType: "sap.kyma.testapp.order.created.v1",
givenApplicationName: "",
givenEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantEventType: "sap.kyma.testapp.Segment1.Segment2.v1",
wantError: false,
},
// invalid even-types
{
name: "fail if the prefix is invalid",
name: "success if the given application name is not clean for non-existing application and event has more than two segments",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sapkyma.testapp.order.created.v1",
wantError: true,
givenApplicationName: "",
givenEventType: "sap.kyma.testapp.Segment1.Segment2.Segment3.Segment4.Segment5.v1",
wantEventType: "sap.kyma.testapp.Segment1Segment2Segment3Segment4.Segment5.v1",
wantError: false,
},
// invalid even-types
{
name: "fail if the prefix is missing",
name: "fail if the prefix is invalid",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "testapp.order.created.v1",
givenEventType: "sapkyma.testapp.Segment1.Segment2.v1",
wantError: true,
},
{
name: "fail if the application name is missing",
name: "fail if the prefix is missing",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sap.kyma.order.created.v1",
givenEventType: "testapp.Segment1.Segment2.v1",
wantError: true,
},
{
name: "fail if the version is missing",
name: "fail if the event-type is incomplete",
givenEventTypePrefix: "sap.kyma",
givenApplicationName: "testapp",
givenEventType: "sap.kyma.testapp.order.created",
givenEventType: "sap.kyma.testapp.Segment1.v1",
wantError: true,
},
}

for _, tc := range testCases {
app := applicationtest.NewApplication(tc.givenApplicationName, tc.givenApplicationLabels)
appLister := fake.NewApplicationListerOrDie(context.Background(), app)
cleaner := NewCleaner(tc.givenEventTypePrefix, appLister, ctrl.Log.WithName("cleaner"))

gotEventType, err := cleaner.Clean(tc.givenEventType)

if tc.wantError == true && err == nil {
t.Errorf("%s: should have failed with an error", tc.name)
continue
}
if tc.wantError != true && err != nil {
t.Errorf("%s: should have succeeded without an error", tc.name)
continue
}
if tc.wantError == true && err != nil {
// error occurred as expected
continue
}
t.Run(tc.name, func(t *testing.T) {
app := applicationtest.NewApplication(tc.givenApplicationName, tc.givenApplicationLabels)
appLister := fake.NewApplicationListerOrDie(context.Background(), app)
cleaner := NewCleaner(tc.givenEventTypePrefix, appLister, ctrl.Log.WithName("cleaner"))
gotEventType, err := cleaner.Clean(tc.givenEventType)

if tc.wantEventType != gotEventType {
t.Errorf("%s: failed event-type[%s] prefix[%s], want event-type [%s] but got [%s]",
tc.name, tc.givenEventType, tc.givenEventTypePrefix, tc.wantEventType, gotEventType)
}
if tc.wantError == true && err == nil {
t.Fatalf("%s: should have failed with an error", tc.name)
}
if tc.wantError != true && err != nil {
t.Fatalf("%s: should have succeeded without an error", tc.name)
}
if tc.wantError == true && err != nil {
// error occurred as expected
return
}
if tc.wantEventType != gotEventType {
t.Fatalf("%s: failed event-type[%s] prefix[%s], want event-type [%s] but got [%s]",
tc.name, tc.givenEventType, tc.givenEventTypePrefix, tc.wantEventType, gotEventType)
}
})
}
}

0 comments on commit 5b30ba9

Please sign in to comment.