dongwei1855 2018-05-23 14:18
浏览 86
已采纳

模拟context.Context测试lambdacontext.FromContext

I'm building an aws lambda using aws-sdk-go and aws-lambda-go and I'm stuck with a little problem.

I want to test my lambda handler. To do so, I need to mock a valid context.Context containing valid attributes for lamdacontext.LambdaContext and satisfy lambdacontext.FromContext.

I cannot seem to find a way to build such mock, since lambdacontext.FromContext always returns me _, false.

Here's my main, with a simple handler on a events.SNSEvent event:

package main

import (
    "context"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-lambda-go/lambdacontext"
)

func main() {
    lambda.Start(handleRequest)
}

func handleRequest(ctx context.Context, snsEvent events.SNSEvent) error {
    lc, ok := lambdacontext.FromContext(ctx); if !ok {
        // Always false
        ...
        return someErr
    }
    . . .
    return nil
}

And here's my test for handleRequest:

package main

import (
    "context"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambdacontext"
    "github.com/stretchr/testify/assert"
    "gitlab.easy-network.it/meg/aml-rekognition/testdata"
    "testing"
)

const imgMock = `
{
  \"some_parameter\": \"some_value\"
}`

func TestHandleRequest(t *testing.T) {

    c := context.Background()

    ctxV := context.WithValue(c, "", map[string]interface{}{
        "AwsRequestID" : "some_aws_id",
        "InvokedFunctionArn" : "some_arn",
        "Identity" : lambdacontext.CognitoIdentity{},
        "ClientContext" : lambdacontext.ClientContext{},
    })

    snsEventMock := events.SNSEvent{
        Records: []events.SNSEventRecord{
            {
                SNS: events.SNSEntity{
                    Message: imgMock,
                },
            },
        },
    }

    err := handleRequest(ctxV, snsEventMock)
    assert.NoError(t, err)

}

I also tried other mocks like passing it a struct with these parameters etc, but I always get false. For instance, I tried also:

type TestMock struct {
    AwsRequestID string
    InvokedFunctionArn string
    Identity lambdacontext.CognitoIdentity
    ClientContext lambdacontext.ClientContext
}

func TestHandleRequest(t *testing.T) {

    c := context.Background()

    testMock := TestMock{
        AwsRequestID : "some_aws_id",
        InvokedFunctionArn : "some_arn",
        Identity : lambdacontext.CognitoIdentity{},
        ClientContext : lambdacontext.ClientContext{},
    }

    ctxV := context.WithValue(c, "", testMock)

    . . .

}

I checked out the source of FromContext and I've been scratching my head for a while.

// LambdaContext is the set of metadata that is passed for every Invoke.
type LambdaContext struct {
    AwsRequestID       string
    InvokedFunctionArn string
    Identity           CognitoIdentity
    ClientContext      ClientContext
}

// An unexported type to be used as the key for types in this package.
// This prevents collisions with keys defined in other packages.
type key struct{}

// The key for a LambdaContext in Contexts.
// Users of this package must use lambdacontext.NewContext and 
lambdacontext.FromContext

// instead of using this key directly.
var contextKey = &key{}

// FromContext returns the LambdaContext value stored in ctx, if any.
func FromContext(ctx context.Context) (*LambdaContext, bool) {
    lc, ok := ctx.Value(contextKey).(*LambdaContext)
    return lc, ok
}

Of course, it returns false even if I just pass a context.Background() to it.

Any idea on how should I build a valid context.Context to let lambdacontext.FromContext return true?

  • 写回答

1条回答 默认 最新

  • doudanma9706 2018-05-23 14:29
    关注

    lambda.FromContext() checks if the passed context.Context contains a value with a "private" key hold inside the lambdacontext package:

    // An unexported type to be used as the key for types in this package.
    // This prevents collisions with keys defined in other packages.
    type key struct{}
    
    // The key for a LambdaContext in Contexts.
    // Users of this package must use lambdacontext.NewContext and lambdacontext.FromContext
    // instead of using this key directly.
    var contextKey = &key{}
    
    // FromContext returns the LambdaContext value stored in ctx, if any.
    func FromContext(ctx context.Context) (*LambdaContext, bool) {
        lc, ok := ctx.Value(contextKey).(*LambdaContext)
        return lc, ok
    }
    

    You cannot access this key, and you can't "reproduce" it (you can't create a value that will be equal to this "private" key).

    But there's an easy way, simply use the lambdacontext.NewContext() to derive a context which will have this key:

    // NewContext returns a new Context that carries value lc.
    func NewContext(parent context.Context, lc *LambdaContext) context.Context {
        return context.WithValue(parent, contextKey, lc)
    }
    

    So the solution:

    ctx := context.Background()
    // Add keys to your liking, then:
    lc := new(lambdacontext.LambdaContext)
    ctx = lambdacontext.NewContext(ctx, lc)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?