Skip to content

Commit

Permalink
Merge pull request #36 from Axway/dev
Browse files Browse the repository at this point in the history
Merge dev to master
  • Loading branch information
jcollins-axway authored Aug 14, 2019
2 parents 916447d + e6b8b81 commit b089c7d
Show file tree
Hide file tree
Showing 7 changed files with 349 additions and 28 deletions.
7 changes: 3 additions & 4 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,50 @@ ACE SDK allows developers to implement microservices that can be used as executa
Implement the callback method that will process the received message. Below is the signature of the method

```
func businessMessageProcessor(ctx context.Context, businessMsg *messaging.BusinessMessage, msgProducer linker.MsgProducer) error
func businessMessageProcessor(executionContext linker.ExecutionContext) error
```

### Execution Context

Get the Open Tracing Span Context

```
ctx := executionContext.GetSpanContext();
```

Get the Business Message list

```
businessMsgs := executionContext.GetBusinessMessages();
```

Get the Message Producer Function

```
msgProducer := executionContext.GetMsgProducer();
```

Get a String Config Value

```
stringParamNameValue := executionContext.GetStringConfigValue("stringParamName");
```

Get an Int Config Value

```
intParamNameValue := executionContext.GetIntConfigValue("intParamName");
```

Get a Boolean Config Value

```
boolParamNameValue := executionContext.GetBooleanConfigValue("boolParamName");
```

### Input processing

The businessMsg parameter of type messaging.BusinessMessage identifies the business message and holds the payload and the metadata associated with the payload.
The businessMsgs is an array of type messaging.BusinessMessage. Each identify a business message and holds the payload and the metadata associated with the payload.

#### Processing payload

Expand Down Expand Up @@ -82,6 +120,24 @@ span.LogFields(opentractingLog.String("event", "processed message"))
span.Finish()
```

## Add log lines (Optional)

ACE SDK sets up a log object that can be used by the service to add additional logging to the console. Using the provided logger will write the lines consistent with the ACE SDK.

A call to the log method and level will include a message and additional fields provided with zap logger calls. The SDK provides field names that may be used.

```
import "github.com/Axway/ace-golang-sdk/util/logging"
var log = logging.Logger()
log.Debug("Business service config",
zap.String(logging.LogFieldServiceName, cfg.ServiceName),
zap.String(logging.LogFieldServiceVersion, cfg.ServiceVersion),
zap.String(logging.LogFieldServiceType, cfg.ServiceType),
zap.String(logging.LogFieldServiceDesc, cfg.ServiceDescription),
)
```

## Handling errors in the service execution

ACE SDK had three error types defined.
Expand Down Expand Up @@ -111,6 +167,9 @@ The service registration needs following details

- Service Name
- Service Version
- Service Type
- NATIVE
- AGGREGATION
- Service Description
- Callback method

Expand Down
130 changes: 130 additions & 0 deletions linker/executionContext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package linker

import (
"context"
"strconv"

"github.com/Axway/ace-golang-sdk/util/logging"
"go.uber.org/zap"

"github.com/Axway/ace-golang-sdk/messaging"
"github.com/Axway/ace-golang-sdk/rpc"
)

const (
stringType = "string"
intType = "int"
boolType = "boolean"
)

// messageContext - Represents the current execution context that holds the message and related properties
type messageContext struct {
ctx context.Context
businessMessages []*messaging.BusinessMessage
configMap map[string]*rpc.ConfigParameter
msgProducer MsgProducer
}

// ExecutionContext - Interface exposed to clients to access the current message context
type ExecutionContext interface {
GetSpanContext() context.Context
GetBusinessMessages() []*messaging.BusinessMessage
GetMsgProducer() MsgProducer
GetStringConfigValue(string) string
GetIntConfigValue(string) int
GetBooleanConfigValue(string) bool
}

// GetSpanContext - Returns the current context
func (msgCtx *messageContext) GetSpanContext() context.Context {
return msgCtx.ctx
}

// GetBusinessMessages - Returns business messages
func (msgCtx *messageContext) GetBusinessMessages() []*messaging.BusinessMessage {
return msgCtx.businessMessages
}

// GetMsgProducer - Returns the interfacee for producing messages
func (msgCtx *messageContext) GetMsgProducer() MsgProducer {
return msgCtx.msgProducer
}

// GetStringConfigValue - Returns the string confign value
func (msgCtx *messageContext) GetStringConfigValue(name string) string {
cfgParam, ok := msgCtx.configMap[name]
if !ok {
log.Warn("The requested configuration did not exist, returning default for type string",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamTypeRequested, stringType))
return ""
}

if cfgParam.GetType() != "string" {
log.Warn("The requested configuration is not correct type, returning default for type string",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamType, cfgParam.GetType()),
zap.String(logging.LogConfigParamTypeRequested, stringType))
return ""
}

return cfgParam.GetValue()
}

// GetIntConfigValue - Returns the int config value
func (msgCtx *messageContext) GetIntConfigValue(name string) int {
cfgParam, ok := msgCtx.configMap[name]
if !ok {
log.Warn("The requested configuration did not exist, returning default for type int",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamTypeRequested, boolType))
return 0
}

if cfgParam.GetType() != "int" {
log.Warn("The requested configuration is not correct type, returning default for type int",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamType, cfgParam.GetType()),
zap.String(logging.LogConfigParamTypeRequested, intType))
return 0
}

intVal, err := strconv.Atoi(cfgParam.GetValue())
if err != nil {
log.Warn("Could not parse the config value to an int, returning default for type int",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamType, cfgParam.GetType()),
zap.String(logging.LogConfigParamTypeRequested, intType))
return 0
}
return intVal
}

// GetBooleanConfigValue - Returns the boolean config value
func (msgCtx *messageContext) GetBooleanConfigValue(name string) bool {
cfgParam, ok := msgCtx.configMap[name]
if !ok {
log.Warn("The requested configuration did not exist, returning default for type boolean",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamTypeRequested, boolType))
return false
}

if cfgParam.GetType() != "boolean" {
log.Warn("The requested configuration is not correct type, returning default for type boolean",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamType, cfgParam.GetType()),
zap.String(logging.LogConfigParamTypeRequested, boolType))
return false
}

boolVal, err := strconv.ParseBool(cfgParam.GetValue())
if err != nil {
log.Warn("Could not parse the config value to a boolean, returning default for type boolean",
zap.String(logging.LogConfigParamName, name),
zap.String(logging.LogConfigParamType, cfgParam.GetType()),
zap.String(logging.LogConfigParamTypeRequested, boolType))
return false
}
return boolVal
}
115 changes: 115 additions & 0 deletions linker/executionContext_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package linker

import (
"context"
"strconv"
"testing"

"github.com/Axway/ace-golang-sdk/messaging"
"github.com/Axway/ace-golang-sdk/rpc"
)

// var testProcBusMsg *messaging.BusinessMessage

var testExecutionContext ExecutionContext

func testBusinessProcess(ec ExecutionContext) error {
testExecutionContext = ec
return nil
}

type testMsgProducer struct{}

// Send -
func (p testMsgProducer) Send(bm *messaging.BusinessMessage) error {
return nil
}

func TestExecutionContext(t *testing.T) {
ctx := context.Background()
msgProducer := testMsgProducer{}
configMap := make(map[string]*rpc.ConfigParameter)

// Add all the config map values we will need
configMap["string-param"] = &rpc.ConfigParameter{
Name: "string-param",
Type: "string",
Value: "string-value",
}
configMap["boolean-param"] = &rpc.ConfigParameter{
Name: "boolean-param",
Type: "boolean",
Value: "true",
}
configMap["int-param"] = &rpc.ConfigParameter{
Name: "int-param",
Type: "int",
Value: "123",
}
configMap["int-param-misconfig"] = &rpc.ConfigParameter{
Name: "int-param",
Type: "int",
Value: "abc",
}

msgContext := messageContext{
ctx: ctx,
msgProducer: msgProducer,
configMap: configMap,
}

testBusinessProcess(&msgContext)

if ctx != testExecutionContext.GetSpanContext() {
t.Error("incorrect Context received from GetSpanContext")
}

// Test GetStringConfigValue
if testExecutionContext.GetStringConfigValue("string-param") != configMap["string-param"].Value {
t.Errorf("The GetStringConfigValue method returned %s but we expected %s", testExecutionContext.GetStringConfigValue("string-param"), configMap["string-param"])
}

if testExecutionContext.GetStringConfigValue("int-param") != "" {
t.Error("The GetStringConfigValue method returned a value for an int type but we expected \"\"")
}

if testExecutionContext.GetStringConfigValue("param-does-not-exist") != "" {
t.Error("The GetStringConfigValue method returned a value for a non existent params but we expected \"\"")
}

// Test GetIntConfigValue
intVal, _ := strconv.Atoi(configMap["int-param"].Value)
if testExecutionContext.GetIntConfigValue("int-param") != intVal {
t.Errorf("The GetIntConfigValue method returned %d but we expected %s", testExecutionContext.GetIntConfigValue("int-param"), configMap["int-param"])
}

if testExecutionContext.GetIntConfigValue("string-param") != 0 {
t.Error("The GetIntConfigValue method returned a value for a string type but we expected 0")
}

if testExecutionContext.GetIntConfigValue("param-does-not-exist") != 0 {
t.Error("The GetIntConfigValue method returned a value for a non existent params but we expected 0")
}

if testExecutionContext.GetIntConfigValue("int-param-misconfig") != 0 {
t.Error("The GetIntConfigValue method returned a value for a non parsable value but we expected 0")
}

// Test GetBooleanConfigValue
boolVal, _ := strconv.ParseBool(configMap["boolean-param"].Value)
if testExecutionContext.GetBooleanConfigValue("boolean-param") != boolVal {
t.Errorf("The GetBooleanConfigValue method returned %t but we expected %s", testExecutionContext.GetBooleanConfigValue("boolean-param"), configMap["boolean-param"])
}

if testExecutionContext.GetBooleanConfigValue("string-param") != false {
t.Error("The GetBooleanConfigValue method returned a value for a string type but we expected false")
}

if testExecutionContext.GetBooleanConfigValue("param-does-not-exist") != false {
t.Error("The GetBooleanConfigValue method returned a value for a non existent params but we expected false")
}

if testExecutionContext.GetBooleanConfigValue("boolean-param-misconfig") != false {
t.Error("The GetBooleanConfigValue method returned a value for a non parsable value but we expected false")
}
}
Loading

0 comments on commit b089c7d

Please sign in to comment.