以前にAWS SDK for Goを使ったテストの書き方を紹介しました。
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 リクエストの送信をやってくれたりします。
サンプルコード
ec2metadata を使って EC2 インスタンス ID を取得するサンプルコードを GitHub にあげています。curl http://169.254.169.254/latest/meta-data/instance-id
と同じことをやっています。
// 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 を返すようにしています。
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) } }