本日も乙

ただの自己満足な備忘録。

AWS SDK for Goのテストの書き方(ec2metadata)

以前にAWS SDK for Goを使ったテストの書き方を紹介しました。

blog.jicoman.info

EC2 や S3 などのサービスは Interface が提供されているのでモックを使ったテストを書くことができます。しかし、EC2メタデータの取得などを行う ec2metadata は Interface がありません。正確に言うと request.Retryer Interface を満たしていますが、ec2iface.EC2API のような ec2metadata 自体の Interface がありません。

ec2metadata の中身を見ると http://169.254.169.254/latest/meta-data/ へ問い合わせしているだけなので HTTP リクエストのテストが行えれば良さそうです。ec2metadata/api_test.go を見ると net/http/httptest を使ったテストを書いているので、これを参考にしてみました。

net/http/httptest とは

HTTP のテストを書くのに便利なパッケージで、擬似的な HTTP サーバを立てて HTTP リクエストの送信をやってくれたりします。

参考記事
budougumi0617.github.io

サンプルコード

ec2metadata を使って EC2 インスタンス ID を取得するサンプルコードを GitHub にあげています。curl http://169.254.169.254/latest/meta-data/instance-id と同じことをやっています。

ec2metadata.go

// GetInstanceID returns EC2 instance ID getting by metadata.
func GetInstanceID(svc *ec2metadata.EC2Metadata) (string, error) {
    return svc.GetMetadata("instance-id")
}

テストコードはこんな感じです。メタデータを擬似サーバとして立てて、/latest/meta-data/instance-id にリクエストしたら EC2 インスタンス ID を返すようにしています。

ec2metadata_test.go

var mockSession = session.Must(session.NewSession(&aws.Config{
    Region: aws.String("mock-region"),
}))

func TestGetInstanceID(t *testing.T) {
    expectedInstanceID := "i-1234567890ab"
    metadataInstanceID := "i-1234567890ab"

    mux := http.NewServeMux()
    mux.HandleFunc("/latest/meta-data/instance-id", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, metadataInstanceID)
    })
    server := httptest.NewServer(mux)
    defer server.Close()

    mockEC2MetaDataSvc := ec2metadata.New(mockSession, &aws.Config{
        Endpoint: aws.String(server.URL),
    })

    instanceID, err := GetInstanceID(mockEC2MetaDataSvc)
    if err != nil {
        t.Errorf("expected no error, but got %v.", err)
    }
    if instanceID != expectedInstanceID {
        t.Errorf("expected value of tag: %s, but got tag value: %v.", expectedInstanceID, instanceID)
    }
}

参考URL