-
-
Notifications
You must be signed in to change notification settings - Fork 257
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Initial commit for adding template data and metadata support * do not error when failing to execute the template * add timestamps * add call template data tests and update readme * improve comment
- Loading branch information
Showing
5 changed files
with
317 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package ghz | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"text/template" | ||
"time" | ||
|
||
"github.com/jhump/protoreflect/desc" | ||
) | ||
|
||
// call template data | ||
type callTemplateData struct { | ||
RequestNumber int64 // unique incrememnted request number for each request | ||
FullyQualifiedName string // fully-qualified name of the method call | ||
MethodName string // shorter call method name | ||
ServiceName string // the service name | ||
InputName string // name of the input message type | ||
OutputName string // name of the output message type | ||
IsClientStreaming bool // whether this call is client streaming | ||
IsServerStreaming bool // whether this call is server streaming | ||
Timestamp string // timestamp of the call in RFC3339 format | ||
TimestampUnix int64 // timestamp of the call as unix time | ||
} | ||
|
||
// newCallTemplateData returns new call template data | ||
func newCallTemplateData(mtd *desc.MethodDescriptor, reqNum int64) *callTemplateData { | ||
now := time.Now() | ||
|
||
return &callTemplateData{ | ||
RequestNumber: reqNum, | ||
FullyQualifiedName: mtd.GetFullyQualifiedName(), | ||
MethodName: mtd.GetName(), | ||
ServiceName: mtd.GetService().GetName(), | ||
InputName: mtd.GetInputType().GetName(), | ||
OutputName: mtd.GetOutputType().GetName(), | ||
IsClientStreaming: mtd.IsClientStreaming(), | ||
IsServerStreaming: mtd.IsServerStreaming(), | ||
Timestamp: now.Format(time.RFC3339), | ||
TimestampUnix: now.Unix(), | ||
} | ||
} | ||
|
||
func (td *callTemplateData) execute(data string) (*bytes.Buffer, error) { | ||
t := template.Must(template.New("call_template_data").Parse(data)) | ||
var tpl bytes.Buffer | ||
err := t.Execute(&tpl, td) | ||
return &tpl, err | ||
} | ||
|
||
func (td *callTemplateData) executeData(data string) (interface{}, error) { | ||
input := []byte(data) | ||
tpl, err := td.execute(data) | ||
if err == nil { | ||
input = tpl.Bytes() | ||
} | ||
|
||
var dataMap interface{} | ||
err = json.Unmarshal(input, &dataMap) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return dataMap, nil | ||
} | ||
|
||
func (td *callTemplateData) executeMetadata(metadata string) (*map[string]string, error) { | ||
input := []byte(metadata) | ||
tpl, err := td.execute(metadata) | ||
if err == nil { | ||
input = tpl.Bytes() | ||
} | ||
|
||
var mdMap map[string]string | ||
err = json.Unmarshal(input, &mdMap) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &mdMap, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package ghz | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/bojand/ghz/protodesc" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCallTemplateData_New(t *testing.T) { | ||
md, err := protodesc.GetMethodDescFromProto("helloworld.Greeter/SayHello", "./testdata/greeter.proto", []string{}) | ||
assert.NoError(t, err) | ||
assert.NotNil(t, md) | ||
|
||
ctd := newCallTemplateData(md, 100) | ||
|
||
assert.NotNil(t, ctd) | ||
assert.Equal(t, int64(100), ctd.RequestNumber) | ||
assert.Equal(t, "helloworld.Greeter.SayHello", ctd.FullyQualifiedName) | ||
assert.Equal(t, "SayHello", ctd.MethodName) | ||
assert.Equal(t, "Greeter", ctd.ServiceName) | ||
assert.Equal(t, "HelloRequest", ctd.InputName) | ||
assert.Equal(t, "HelloReply", ctd.OutputName) | ||
assert.Equal(t, false, ctd.IsClientStreaming) | ||
assert.Equal(t, false, ctd.IsServerStreaming) | ||
assert.NotEmpty(t, ctd.Timestamp) | ||
assert.NotZero(t, ctd.TimestampUnix) | ||
} | ||
|
||
func TestCallTemplateData_ExecuteData(t *testing.T) { | ||
md, err := protodesc.GetMethodDescFromProto("helloworld.Greeter/SayHello", "./testdata/greeter.proto", []string{}) | ||
assert.NoError(t, err) | ||
assert.NotNil(t, md) | ||
|
||
ctd := newCallTemplateData(md, 200) | ||
|
||
assert.NotNil(t, ctd) | ||
|
||
var tests = []struct { | ||
name string | ||
in string | ||
expected interface{} | ||
expectError bool | ||
}{ | ||
{"no template", | ||
`{"name":"bob"}`, | ||
map[string]interface{}{"name": "bob"}, | ||
false, | ||
}, | ||
{"with template", | ||
`{"name":"{{.RequestNumber}} bob {{.FullyQualifiedName}} {{.MethodName}} {{.ServiceName}} {{.InputName}} {{.OutputName}} {{.IsClientStreaming}} {{.IsServerStreaming}}"}`, | ||
map[string]interface{}{"name": "200 bob helloworld.Greeter.SayHello SayHello Greeter HelloRequest HelloReply false false"}, | ||
false, | ||
}, | ||
{"with unknown action", | ||
`{"name":"asdf {{.Something}} {{.MethodName}} bob"}`, | ||
map[string]interface{}{"name": "asdf {{.Something}} {{.MethodName}} bob"}, | ||
false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
r, err := ctd.executeData(tt.in) | ||
if tt.expectError { | ||
assert.Error(t, err) | ||
} else { | ||
assert.NoError(t, err) | ||
} | ||
|
||
assert.Equal(t, tt.expected, r) | ||
}) | ||
} | ||
} | ||
|
||
func TestCallTemplateData_ExecuteMetadata(t *testing.T) { | ||
md, err := protodesc.GetMethodDescFromProto("helloworld.Greeter/SayHello", "./testdata/greeter.proto", []string{}) | ||
assert.NoError(t, err) | ||
assert.NotNil(t, md) | ||
|
||
ctd := newCallTemplateData(md, 200) | ||
|
||
assert.NotNil(t, ctd) | ||
|
||
var tests = []struct { | ||
name string | ||
in string | ||
expected interface{} | ||
expectError bool | ||
}{ | ||
{"no template", | ||
`{"trace_id":"asdf"}`, | ||
&map[string]string{"trace_id": "asdf"}, | ||
false, | ||
}, | ||
{"with template", | ||
`{"trace_id":"{{.RequestNumber}} asdf {{.FullyQualifiedName}} {{.MethodName}} {{.ServiceName}} {{.InputName}} {{.OutputName}} {{.IsClientStreaming}} {{.IsServerStreaming}}"}`, | ||
&map[string]string{"trace_id": "200 asdf helloworld.Greeter.SayHello SayHello Greeter HelloRequest HelloReply false false"}, | ||
false, | ||
}, | ||
{"with unknown action", | ||
`{"trace_id":"asdf {{.Something}} {{.MethodName}} bob"}`, | ||
&map[string]string{"trace_id": "asdf {{.Something}} {{.MethodName}} bob"}, | ||
false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
r, err := ctd.executeMetadata(tt.in) | ||
if tt.expectError { | ||
assert.Error(t, err) | ||
} else { | ||
assert.NoError(t, err) | ||
} | ||
|
||
assert.Equal(t, tt.expected, r) | ||
}) | ||
} | ||
} |
Oops, something went wrong.