Repository: cloudevents/sdk-go
Pull request #373 (2020-03-12 14:37:57)

Transformers changes
* Modified AddUUID in SetUUID (now it imposes the Id of the event to UUID)
* Added benchmarks to compare transformers with changes directly on `Event` data structure


Patch:
diff --git a/pkg/binding/transformer/add_metadata.go b/pkg/binding/transformer/add_metadata.go
index a45b5e3..23805ed 100644
--- a/pkg/binding/transformer/add_metadata.go
+++ b/pkg/binding/transformer/add_metadata.go
@@ -10,25 +10,25 @@ import (
 
 // Add cloudevents attribute (if missing) during the encoding process
 func AddAttribute(attributeKind spec.Kind, value interface{}) binding.TransformerFactory {
-	return setAttributeTranscoderFactory{attributeKind: attributeKind, value: value}
+	return addAttributeTransformerFactory{attributeKind: attributeKind, value: value}
 }
 
 // Add cloudevents extension (if missing) during the encoding process
 func AddExtension(name string, value interface{}) binding.TransformerFactory {
-	return setExtensionTranscoderFactory{name: name, value: value}
+	return addExtensionTransformerFactory{name: name, value: value}
 }
 
-type setAttributeTranscoderFactory struct {
+type addAttributeTransformerFactory struct {
 	attributeKind spec.Kind
 	value         interface{}
 }
 
-func (a setAttributeTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a addAttributeTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a setAttributeTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
-	return &setAttributeTransformer{
+func (a addAttributeTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+	return &addAttributeTransformer{
 		BinaryWriter:  encoder,
 		attributeKind: a.attributeKind,
 		value:         a.value,
@@ -36,7 +36,7 @@ func (a setAttributeTranscoderFactory) BinaryTransformer(encoder binding.BinaryW
 	}
 }
 
-func (a setAttributeTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a addAttributeTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		v := spec.VS.Version(event.SpecVersion())
 		if v == nil {
@@ -49,17 +49,17 @@ func (a setAttributeTranscoderFactory) EventTransformer() binding.EventTransform
 	}
 }
 
-type setExtensionTranscoderFactory struct {
+type addExtensionTransformerFactory struct {
 	name  string
 	value interface{}
 }
 
-func (a setExtensionTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a addExtensionTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a setExtensionTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
-	return &setExtensionTransformer{
+func (a addExtensionTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+	return &addExtensionTransformer{
 		BinaryWriter: encoder,
 		name:         a.name,
 		value:        a.value,
@@ -67,7 +67,7 @@ func (a setExtensionTranscoderFactory) BinaryTransformer(encoder binding.BinaryW
 	}
 }
 
-func (a setExtensionTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a addExtensionTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		if _, ok := event.Extensions()[a.name]; !ok {
 			return event.Context.SetExtension(a.name, a.value)
@@ -76,7 +76,7 @@ func (a setExtensionTranscoderFactory) EventTransformer() binding.EventTransform
 	}
 }
 
-type setAttributeTransformer struct {
+type addAttributeTransformer struct {
 	binding.BinaryWriter
 	attributeKind spec.Kind
 	value         interface{}
@@ -84,7 +84,7 @@ type setAttributeTransformer struct {
 	found         bool
 }
 
-func (b *setAttributeTransformer) SetAttribute(attribute spec.Attribute, value interface{}) error {
+func (b *addAttributeTransformer) SetAttribute(attribute spec.Attribute, value interface{}) error {
 	if attribute.Kind() == b.attributeKind {
 		b.found = true
 	}
@@ -92,7 +92,7 @@ func (b *setAttributeTransformer) SetAttribute(attribute spec.Attribute, value i
 	return b.BinaryWriter.SetAttribute(attribute, value)
 }
 
-func (b *setAttributeTransformer) End() error {
+func (b *addAttributeTransformer) End() error {
 	if !b.found {
 		err := b.BinaryWriter.SetAttribute(b.version.AttributeFromKind(b.attributeKind), b.value)
 		if err != nil {
@@ -102,21 +102,21 @@ func (b *setAttributeTransformer) End() error {
 	return b.BinaryWriter.End()
 }
 
-type setExtensionTransformer struct {
+type addExtensionTransformer struct {
 	binding.BinaryWriter
 	name  string
 	value interface{}
 	found bool
 }
 
-func (b *setExtensionTransformer) SetExtension(name string, value interface{}) error {
+func (b *addExtensionTransformer) SetExtension(name string, value interface{}) error {
 	if name == b.name {
 		b.found = true
 	}
 	return b.BinaryWriter.SetExtension(name, value)
 }
 
-func (b *setExtensionTransformer) End() error {
+func (b *addExtensionTransformer) End() error {
 	if !b.found {
 		err := b.BinaryWriter.SetExtension(b.name, b.value)
 		if err != nil {
diff --git a/pkg/binding/transformer/default_metadata.go b/pkg/binding/transformer/default_metadata.go
index ba74e9e..a68becb 100644
--- a/pkg/binding/transformer/default_metadata.go
+++ b/pkg/binding/transformer/default_metadata.go
@@ -12,58 +12,41 @@ import (
 )
 
 var (
-	// Sets the cloudevents id attribute (if missing) to a UUID.New()
-	AddUUID binding.TransformerFactory = addUUID{}
-	// Sets the cloudevents time attribute (if missing) to time.Now()
+	// Sets the cloudevents id attribute to a UUID.New()
+	SetUUID binding.TransformerFactory = setUUID{}
+	// Add the cloudevents time attribute, if missing, to time.Now()
 	AddTimeNow binding.TransformerFactory = addTimeNow{}
 )
 
-type addUUID struct{}
+type setUUID struct{}
 
-func (a addUUID) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a setUUID) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a addUUID) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
-	return &addUUIDTransformer{
+func (a setUUID) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+	return &setUUIDTransformer{
 		BinaryWriter: encoder,
-		found:        false,
 	}
 }
 
-func (a addUUID) EventTransformer() binding.EventTransformer {
+func (a setUUID) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
-		if event.Context.GetID() == "" {
-			return event.Context.SetID(uuid.New().String())
-		}
-		return nil
+		return event.Context.SetID(uuid.New().String())
 	}
 }
 
-type addUUIDTransformer struct {
+type setUUIDTransformer struct {
 	binding.BinaryWriter
-	version spec.Version
-	found   bool
 }
 
-func (b *addUUIDTransformer) SetAttribute(attribute spec.Attribute, value interface{}) error {
+func (b *setUUIDTransformer) SetAttribute(attribute spec.Attribute, value interface{}) error {
 	if attribute.Kind() == spec.ID {
-		b.found = true
+		return b.BinaryWriter.SetAttribute(attribute.Version().AttributeFromKind(spec.ID), uuid.New().String())
 	}
-	b.version = attribute.Version()
 	return b.BinaryWriter.SetAttribute(attribute, value)
 }
 
-func (b *addUUIDTransformer) End() error {
-	if !b.found {
-		err := b.BinaryWriter.SetAttribute(b.version.AttributeFromKind(spec.ID), uuid.New().String())
-		if err != nil {
-			return err
-		}
-	}
-	return b.BinaryWriter.End()
-}
-
 type addTimeNow struct{}
 
 func (a addTimeNow) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
diff --git a/pkg/binding/transformer/delete_metadata.go b/pkg/binding/transformer/delete_metadata.go
index e67da1c..4d99ef2 100644
--- a/pkg/binding/transformer/delete_metadata.go
+++ b/pkg/binding/transformer/delete_metadata.go
@@ -10,30 +10,30 @@ import (
 
 // Delete cloudevents attribute during the encoding process
 func DeleteAttribute(attributeKind spec.Kind) binding.TransformerFactory {
-	return deleteAttributeTranscoderFactory{attributeKind: attributeKind}
+	return deleteAttributeTransformerFactory{attributeKind: attributeKind}
 }
 
 // Delete cloudevents extension during the encoding process
 func DeleteExtension(name string) binding.TransformerFactory {
-	return deleteExtensionTranscoderFactory{name: name}
+	return deleteExtensionTransformerFactory{name: name}
 }
 
-type deleteAttributeTranscoderFactory struct {
+type deleteAttributeTransformerFactory struct {
 	attributeKind spec.Kind
 }
 
-func (a deleteAttributeTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a deleteAttributeTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a deleteAttributeTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+func (a deleteAttributeTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
 	return &deleteAttributeTransformer{
 		BinaryWriter:  encoder,
 		attributeKind: a.attributeKind,
 	}
 }
 
-func (a deleteAttributeTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a deleteAttributeTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		v := spec.VS.Version(event.SpecVersion())
 		if v == nil {
@@ -46,22 +46,22 @@ func (a deleteAttributeTranscoderFactory) EventTransformer() binding.EventTransf
 	}
 }
 
-type deleteExtensionTranscoderFactory struct {
+type deleteExtensionTransformerFactory struct {
 	name string
 }
 
-func (a deleteExtensionTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a deleteExtensionTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a deleteExtensionTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+func (a deleteExtensionTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
 	return &deleteExtensionTransformer{
 		BinaryWriter: encoder,
 		name:         a.name,
 	}
 }
 
-func (a deleteExtensionTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a deleteExtensionTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		return event.Context.SetExtension(a.name, nil)
 	}
diff --git a/pkg/binding/transformer/update_metadata.go b/pkg/binding/transformer/update_metadata.go
index 26d9c3d..f4e32c1 100644
--- a/pkg/binding/transformer/update_metadata.go
+++ b/pkg/binding/transformer/update_metadata.go
@@ -10,24 +10,24 @@ import (
 
 // Update cloudevents attribute (if present) using the provided function
 func UpdateAttribute(attributeKind spec.Kind, updater func(interface{}) (interface{}, error)) binding.TransformerFactory {
-	return updateAttributeTranscoderFactory{attributeKind: attributeKind, updater: updater}
+	return updateAttributeTransformerFactory{attributeKind: attributeKind, updater: updater}
 }
 
 // Update cloudevents extension (if present) using the provided function
 func UpdateExtension(name string, updater func(interface{}) (interface{}, error)) binding.TransformerFactory {
-	return updateExtensionTranscoderFactory{name: name, updater: updater}
+	return updateExtensionTransformerFactory{name: name, updater: updater}
 }
 
-type updateAttributeTranscoderFactory struct {
+type updateAttributeTransformerFactory struct {
 	attributeKind spec.Kind
 	updater       func(interface{}) (interface{}, error)
 }
 
-func (a updateAttributeTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a updateAttributeTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a updateAttributeTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+func (a updateAttributeTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
 	return &updateAttributeTransformer{
 		BinaryWriter:  encoder,
 		attributeKind: a.attributeKind,
@@ -35,7 +35,7 @@ func (a updateAttributeTranscoderFactory) BinaryTransformer(encoder binding.Bina
 	}
 }
 
-func (a updateAttributeTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a updateAttributeTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		v := spec.VS.Version(event.SpecVersion())
 		if v == nil {
@@ -56,16 +56,16 @@ func (a updateAttributeTranscoderFactory) EventTransformer() binding.EventTransf
 	}
 }
 
-type updateExtensionTranscoderFactory struct {
+type updateExtensionTransformerFactory struct {
 	name    string
 	updater func(interface{}) (interface{}, error)
 }
 
-func (a updateExtensionTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (a updateExtensionTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil
 }
 
-func (a updateExtensionTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+func (a updateExtensionTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
 	return &updateExtensionTransformer{
 		BinaryWriter: encoder,
 		name:         a.name,
@@ -73,7 +73,7 @@ func (a updateExtensionTranscoderFactory) BinaryTransformer(encoder binding.Bina
 	}
 }
 
-func (a updateExtensionTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (a updateExtensionTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(event *event.Event) error {
 		if val, ok := event.Extensions()[a.name]; ok {
 			newVal, err := a.updater(val)
diff --git a/pkg/binding/transformer/version.go b/pkg/binding/transformer/version.go
index 4af9421..e95c3ae 100644
--- a/pkg/binding/transformer/version.go
+++ b/pkg/binding/transformer/version.go
@@ -8,22 +8,22 @@ import (
 
 // Converts the event context version to the specified one.
 func Version(version spec.Version) binding.TransformerFactory {
-	return versionTranscoderFactory{version: version}
+	return versionTransformerFactory{version: version}
 }
 
-type versionTranscoderFactory struct {
+type versionTransformerFactory struct {
 	version spec.Version
 }
 
-func (v versionTranscoderFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
+func (v versionTransformerFactory) StructuredTransformer(binding.StructuredWriter) binding.StructuredWriter {
 	return nil // Not supported, must fallback to EventTransformer!
 }
 
-func (v versionTranscoderFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
+func (v versionTransformerFactory) BinaryTransformer(encoder binding.BinaryWriter) binding.BinaryWriter {
 	return binaryVersionTransformer{BinaryWriter: encoder, version: v.version}
 }
 
-func (v versionTranscoderFactory) EventTransformer() binding.EventTransformer {
+func (v versionTransformerFactory) EventTransformer() binding.EventTransformer {
 	return func(e *event.Event) error {
 		e.Context = v.version.Convert(e.Context)
 		return nil


Test patch:
diff --git a/pkg/binding/transformer/default_metadata_test.go b/pkg/binding/transformer/default_metadata_test.go
index 9700f1a..67b5ef6 100644
--- a/pkg/binding/transformer/default_metadata_test.go
+++ b/pkg/binding/transformer/default_metadata_test.go
@@ -15,12 +15,7 @@ import (
 	. "github.com/cloudevents/sdk-go/pkg/binding/test"
 )
 
-func TestAddUUID(t *testing.T) {
-	eventWithoutId := test.MinEvent()
-	eventCtx := eventWithoutId.Context.AsV1()
-	eventCtx.ID = ""
-	eventWithoutId.Context = eventCtx
-
+func TestSetUUID(t *testing.T) {
 	eventWithId := test.MinEvent()
 
 	assertUUID := func(t *testing.T, ev event.Event) {
@@ -31,34 +26,22 @@ func TestAddUUID(t *testing.T) {
 
 	RunTransformerTests(t, context.Background(), []TransformerTestArgs{
 		{
-			Name:         "No change to id to Mock Structured message",
+			Name:         "Set UUID when id already exists to Mock Structured message",
 			InputMessage: test.MustCreateMockStructuredMessage(eventWithId.Clone()),
-			WantEvent:    eventWithId.Clone(),
-			Transformers: []binding.TransformerFactory{AddUUID},
+			AssertFunc:   assertUUID,
+			Transformers: []binding.TransformerFactory{SetUUID},
 		},
 		{
-			Name:         "No change to id to Mock Binary message",
+			Name:         "Set UUID when id already exists to Mock Binary message",
 			InputMessage: test.MustCreateMockBinaryMessage(eventWithId.Clone()),
-			WantEvent:    eventWithId.Clone(),
-			Transformers: []binding.TransformerFactory{AddUUID},
-		},
-		{
-			Name:         "No change to id to Event message",
-			InputEvent:   eventWithId,
-			WantEvent:    eventWithId,
-			Transformers: []binding.TransformerFactory{AddUUID},
-		},
-		{
-			Name:         "Add UUID to Mock Binary message",
-			InputMessage: test.MustCreateMockBinaryMessage(eventWithoutId.Clone()),
 			AssertFunc:   assertUUID,
-			Transformers: []binding.TransformerFactory{AddUUID},
+			Transformers: []binding.TransformerFactory{SetUUID},
 		},
 		{
-			Name:         "Add UUID to Event message",
-			InputEvent:   eventWithoutId,
+			Name:         "Set UUID when id already exists to Event message",
+			InputEvent:   eventWithId,
 			AssertFunc:   assertUUID,
-			Transformers: []binding.TransformerFactory{AddUUID},
+			Transformers: []binding.TransformerFactory{SetUUID},
 		},
 	})
 }
diff --git a/test/benchmark/buffering_vs_to_event/http_transformers_benchmark_test.go b/test/benchmark/buffering_vs_to_event/http_transformers_benchmark_test.go
new file mode 100644
index 0000000..414cc6f
--- /dev/null
+++ b/test/benchmark/buffering_vs_to_event/http_transformers_benchmark_test.go
@@ -0,0 +1,174 @@
+package buffering_vs_to_event_test
+
+import (
+	"context"
+	nethttp "net/http"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/cloudevents/sdk-go/pkg/binding"
+	"github.com/cloudevents/sdk-go/pkg/binding/buffering"
+	"github.com/cloudevents/sdk-go/pkg/binding/test"
+	"github.com/cloudevents/sdk-go/pkg/binding/transformer"
+	"github.com/cloudevents/sdk-go/pkg/event"
+	"github.com/cloudevents/sdk-go/pkg/transport/http"
+	"github.com/cloudevents/sdk-go/pkg/types"
+)
+
+var (
+	binaryHttpRequest       *nethttp.Request
+	binaryHttpRequestNoData *nethttp.Request
+
+	transformers binding.TransformerFactories
+
+	ctx = context.TODO()
+)
+
+func init() {
+	initialEvent := test.FullEvent()
+	initialEvent.SetExtension("key", "aaa")
+
+	binaryHttpRequest, _ = nethttp.NewRequest("POST", "http://localhost", nil)
+	Err = http.WriteRequest(context.TODO(), binding.ToEventMessage(&initialEvent), binaryHttpRequest, nil)
+	if Err != nil {
+		panic(Err)
+	}
+
+	initialEventNoData := test.FullEvent()
+	initialEventNoData.Data = nil
+	initialEventNoData.SetDataContentType("")
+	initialEventNoData.SetExtension("key", "aaa")
+
+	binaryHttpRequestNoData, _ = nethttp.NewRequest("POST", "http://localhost", nil)
+	Err = http.WriteRequest(context.TODO(), binding.ToEventMessage(&initialEventNoData), binaryHttpRequestNoData, nil)
+	if Err != nil {
+		panic(Err)
+	}
+
+	transformers = append(binding.TransformerFactories{},
+		transformer.SetExtension("aaa", "AAAA", func(i2 interface{}) (interface{}, error) {
+			vStr, err := types.Format(i2)
+			if err != nil {
+				return nil, err
+			}
+			return strings.ToUpper(vStr), nil
+		})...,
+	)
+	transformers = append(transformers,
+		transformer.SetExtension("aTime", time.Now(), func(i2 interface{}) (interface{}, error) {
+			vTime, err := types.ToTime(i2)
+			if err != nil {
+				return nil, err
+			}
+			return vTime.Add(3 * time.Hour), nil
+		})...,
+	)
+}
+
+var Req *nethttp.Request
+
+func BenchmarkHttpWithToEvent(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequest)
+		E, Err = binding.ToEvent(ctx, M, nil)
+		if Err != nil {
+			panic(Err)
+		}
+		transformEvent(E)
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, binding.ToEventMessage(E), Req, nil)
+	}
+}
+
+func BenchmarkNoDataHttpWithToEvent(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequestNoData)
+		E, Err = binding.ToEvent(ctx, M, nil)
+		if Err != nil {
+			panic(Err)
+		}
+		transformEvent(E)
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, binding.ToEventMessage(E), Req, nil)
+	}
+}
+
+func BenchmarkHttpWithBuffering(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequest)
+		M, Err = buffering.CopyMessage(ctx, M, transformers)
+		if Err != nil {
+			panic(Err)
+		}
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, M, Req, nil)
+	}
+}
+
+func BenchmarkHttpWithDirect(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequest)
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, M, Req, transformers)
+	}
+}
+
+func BenchmarkNoDataHttpWithBuffering(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequestNoData)
+		M, Err = buffering.CopyMessage(ctx, M, transformers)
+		if Err != nil {
+			panic(Err)
+		}
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, M, Req, nil)
+	}
+}
+
+func BenchmarkNoDataHttpWithDirect(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		M = http.NewMessageFromHttpRequest(binaryHttpRequestNoData)
+		Req, Err = nethttp.NewRequest("POST", "http://localhost", nil)
+		if Err != nil {
+			panic(Err)
+		}
+		Err = http.WriteRequest(ctx, M, Req, transformers)
+	}
+}
+
+func transformEvent(e *event.Event) {
+	if v, ok := e.Extensions()["aaa"]; ok {
+		vStr, err := types.Format(v)
+		if err != nil {
+			panic(err)
+		}
+		e.SetExtension("aaa", strings.ToUpper(vStr))
+	} else {
+		e.SetExtension("aaa", strings.ToUpper("AAA"))
+	}
+	if v, ok := e.Extensions()["aTime"]; ok {
+		vTime, err := types.ToTime(v)
+		if err != nil {
+			panic(err)
+		}
+		e.SetExtension("aTime", vTime.Add(3*time.Hour))
+	} else {
+		e.SetExtension("aTime", time.Now().UTC().Round(0))
+	}
+}
diff --git a/test/benchmark/buffering_vs_to_event/transformers_benchmark_test.go b/test/benchmark/buffering_vs_to_event/transformers_benchmark_test.go
new file mode 100644
index 0000000..d928ac8
--- /dev/null
+++ b/test/benchmark/buffering_vs_to_event/transformers_benchmark_test.go
@@ -0,0 +1,87 @@
+package buffering_vs_to_event_test
+
+import (
+	"context"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/cloudevents/sdk-go/pkg/binding"
+	"github.com/cloudevents/sdk-go/pkg/binding/buffering"
+	"github.com/cloudevents/sdk-go/pkg/binding/test"
+	"github.com/cloudevents/sdk-go/pkg/binding/transformer"
+	"github.com/cloudevents/sdk-go/pkg/event"
+	"github.com/cloudevents/sdk-go/pkg/types"
+)
+
+var M binding.Message
+var E *event.Event
+var Err error
+
+func BenchmarkBase(b *testing.B) {
+	initialEvent := test.FullEvent()
+	initialEvent.SetExtension("aaa", "bbb")
+	for i := 0; i < b.N; i++ {
+		M = test.MustCreateMockBinaryMessage(initialEvent)
+	}
+}
+
+func BenchmarkToEventAndUpdateExtensions(b *testing.B) {
+	initialEvent := test.FullEvent()
+	ctx := context.TODO()
+	initialEvent.SetExtension("aaa", "bbb")
+	for i := 0; i < b.N; i++ {
+		M = test.MustCreateMockBinaryMessage(initialEvent)
+		E, _ = binding.ToEvent(ctx, M, nil)
+		if v, ok := E.Extensions()["aaa"]; ok {
+			vStr, err := types.Format(v)
+			if err != nil {
+				panic(err)
+			}
+			E.SetExtension("aaa", strings.ToUpper(vStr))
+		} else {
+			E.SetExtension("aaa", strings.ToUpper("AAA"))
+		}
+		if v, ok := E.Extensions()["aTime"]; ok {
+			vTime, err := types.ToTime(v)
+			if err != nil {
+				panic(err)
+			}
+			E.SetExtension("aTime", vTime.Add(3*time.Hour))
+		} else {
+			E.SetExtension("aTime", time.Now().UTC().Round(0))
+		}
+
+	}
+}
+
+func BenchmarkBufferingAndUpdateExtensions(b *testing.B) {
+	initialEvent := test.FullEvent()
+	ctx := context.TODO()
+	initialEvent.SetExtension("aaa", "bbb")
+
+	transformers := binding.TransformerFactories{}
+	transformers = append(transformers,
+		transformer.SetExtension("aaa", "AAAA", func(i2 interface{}) (interface{}, error) {
+			vStr, err := types.Format(i2)
+			if err != nil {
+				return nil, err
+			}
+			return strings.ToUpper(vStr), nil
+		})...,
+	)
+	transformers = append(transformers,
+		transformer.SetExtension("aTime", time.Now(), func(i2 interface{}) (interface{}, error) {
+			vTime, err := types.ToTime(i2)
+			if err != nil {
+				return nil, err
+			}
+			return vTime.Add(3 * time.Hour), nil
+		})...,
+	)
+
+	for i := 0; i < b.N; i++ {
+		M = test.MustCreateMockBinaryMessage(initialEvent)
+		M, _ = buffering.CopyMessage(ctx, M, transformers)
+	}
+}