浏览代码

improve test cases for instance_metadata.go

Jackson Tian 7 年之前
父节点
当前提交
eb79f24170
共有 2 个文件被更改,包括 239 次插入40 次删除
  1. 43 23
      sdk/auth/credentials/providers/instance_metadata.go
  2. 196 17
      sdk/auth/credentials/providers/instance_metadata_test.go

+ 43 - 23
sdk/auth/credentials/providers/instance_metadata.go

@@ -21,40 +21,60 @@ type InstanceMetadataProvider struct {
 	RoleName string
 }
 
+func get(url string) (status int, content string, err error) {
+	resp, err := http.Get(url)
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+
+	bodyBytes, err := ioutil.ReadAll(resp.Body)
+	return resp.StatusCode, string(bodyBytes), err
+}
+
+func (p *InstanceMetadataProvider) GetRoleName() (roleName string, err error) {
+	// Instances can have only one role name that never changes,
+	// so attempt to populate it.
+	// If this call is executed in an environment that doesn't support instance metadata,
+	// it will time out after 30 seconds and return an err.
+	status, roleName, err := get(securityCredURL)
+
+	if err != nil {
+		return
+	}
+
+	if status != 200 {
+		err = fmt.Errorf("received %d getting role name: %s", status, roleName)
+		return
+	}
+
+	if roleName == "" {
+		err = errors.New("unable to retrieve role name, it may be unset")
+	}
+
+	return
+}
+
 func (p *InstanceMetadataProvider) Retrieve() (auth.Credential, error) {
 	if p.RoleName == "" {
-		// Instances can have only one role name that never changes,
-		// so attempt to populate it.
-		// If this call is executed in an environment that doesn't support instance metadata,
-		// it will time out after 30 seconds and return an err.
-		resp, err := http.Get(securityCredURL)
+		roleName, err := p.GetRoleName()
 		if err != nil {
 			return nil, err
 		}
-		defer resp.Body.Close()
-
-		bodyBytes, _ := ioutil.ReadAll(resp.Body)
-		if resp.StatusCode != 200 {
-			return nil, fmt.Errorf("received %d getting role name: %s", resp.StatusCode, bodyBytes)
-		}
-		roleName := string(bodyBytes)
-		if roleName == "" {
-			return nil, errors.New("unable to retrieve role name, it may be unset")
-		}
 		p.RoleName = roleName
 	}
 
-	resp, err := http.Get(securityCredURL + p.RoleName)
+	status, content, err := get(securityCredURL + p.RoleName)
 	if err != nil {
 		return nil, err
 	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("received %d getting security credentials for %s", resp.StatusCode, p.RoleName)
+	if status != 200 {
+		return nil, fmt.Errorf("received %d getting security credentials for %s", status, p.RoleName)
 	}
+
 	body := make(map[string]interface{})
-	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
+
+	if err := json.Unmarshal([]byte(content), &body); err != nil {
 		return nil, err
 	}
 
@@ -76,11 +96,11 @@ func (p *InstanceMetadataProvider) Retrieve() (auth.Credential, error) {
 func extractString(m map[string]interface{}, key string) (string, error) {
 	raw, ok := m[key]
 	if !ok {
-		return "", fmt.Errorf("%s not in %+v", key, m)
+		return "", fmt.Errorf("%s not in map", key)
 	}
 	str, ok := raw.(string)
 	if !ok {
-		return "", fmt.Errorf("%s is not a string in %+v", key, m)
+		return "", fmt.Errorf("%s is not a string in map", key)
 	}
 	return str, nil
 }

+ 196 - 17
sdk/auth/credentials/providers/instance_metadata_test.go

@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+	"github.com/stretchr/testify/assert"
 )
 
 func TestInstanceMetadataProvider_Retrieve_Success(t *testing.T) {
@@ -32,8 +33,8 @@ func TestInstanceMetadataProvider_Retrieve_Success(t *testing.T) {
 			}`
 			status = 200
 		}
-		w.Write([]byte(body))
 		w.WriteHeader(status)
+		w.Write([]byte(body))
 	}))
 	defer ts.Close()
 
@@ -45,22 +46,200 @@ func TestInstanceMetadataProvider_Retrieve_Success(t *testing.T) {
 	}()
 
 	credential, err := NewInstanceMetadataProvider().Retrieve()
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.Nil(t, err)
 
 	stsTokenCredential, ok := credential.(*credentials.StsTokenCredential)
-	if !ok {
-		t.Fatal("expected AccessKeyCredential")
-	}
-
-	if stsTokenCredential.AccessKeyId != "STS.L4aBSCSJVMuKg5U1vFDw" {
-		t.Fatalf("expected AccessKeyId STS.L4aBSCSJVMuKg5U1vFDw but received %s", stsTokenCredential.AccessKeyId)
-	}
-	if stsTokenCredential.AccessKeySecret != "wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pKCNZ9" {
-		t.Fatalf("expected AccessKeySecret wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pKCNZ9 but received %s", stsTokenCredential.AccessKeySecret)
-	}
-	if !strings.HasPrefix(stsTokenCredential.AccessKeyStsToken, "CAESrAIIARKAA") {
-		t.Fatalf("expected AccessKeyStsToken starting with CAESrAIIARKAA but received %s", stsTokenCredential.AccessKeyStsToken)
-	}
+	assert.True(t, ok)
+
+	assert.Equal(t, "STS.L4aBSCSJVMuKg5U1vFDw", stsTokenCredential.AccessKeyId)
+	assert.Equal(t, "wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pKCNZ9", stsTokenCredential.AccessKeySecret)
+	assert.True(t, strings.HasPrefix(stsTokenCredential.AccessKeyStsToken, "CAESrAIIARKAA"))
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail1(t *testing.T) {
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", "http://invalid", -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	message := err.Error()
+	assert.True(t, strings.HasSuffix(message, "no such host"))
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail2(t *testing.T) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		var body string
+		var status int
+
+		switch r.URL.Path {
+		case "/latest/meta-data/ram/security-credentials/":
+			body = "ELK"
+			status = 400
+		}
+		w.WriteHeader(status)
+		w.Write([]byte(body))
+	}))
+	defer ts.Close()
+
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", ts.URL, -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	assert.Equal(t, "received 400 getting role name: ELK", err.Error())
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail3(t *testing.T) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		var body string
+		var status int
+
+		switch r.URL.Path {
+		case "/latest/meta-data/ram/security-credentials/":
+			body = ""
+			status = 200
+		}
+		w.WriteHeader(status)
+		w.Write([]byte(body))
+	}))
+	defer ts.Close()
+
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", ts.URL, -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	assert.Equal(t, "unable to retrieve role name, it may be unset", err.Error())
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail4(t *testing.T) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		var body string
+		var status int
+
+		switch r.URL.Path {
+		case "/latest/meta-data/ram/security-credentials/":
+			body = "ELK"
+			status = 200
+		case "/latest/meta-data/ram/security-credentials/ELK":
+			body = ``
+			status = 404
+		}
+		w.WriteHeader(status)
+		w.Write([]byte(body))
+	}))
+	defer ts.Close()
+
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", ts.URL, -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	assert.Equal(t, "received 404 getting security credentials for ELK", err.Error())
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail5(t *testing.T) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		var body string
+		var status int
+
+		switch r.URL.Path {
+		case "/latest/meta-data/ram/security-credentials/":
+			body = "ELK"
+			status = 200
+		case "/latest/meta-data/ram/security-credentials/ELK":
+			body = `invalid json`
+			status = 200
+		}
+		w.WriteHeader(status)
+		w.Write([]byte(body))
+	}))
+	defer ts.Close()
+
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", ts.URL, -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	assert.Equal(t, "invalid character 'i' looking for beginning of value", err.Error())
+}
+
+func mockServer(json string) (server *httptest.Server) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		var body string
+		var status int
+
+		switch r.URL.Path {
+		case "/latest/meta-data/ram/security-credentials/":
+			body = "ELK"
+			status = 200
+		case "/latest/meta-data/ram/security-credentials/ELK":
+			body = json
+			status = 200
+		}
+		w.WriteHeader(status)
+		w.Write([]byte(body))
+	}))
+	return ts
+}
+
+func test(t *testing.T, input, expected string) {
+	// Start a test server locally.
+	ts := mockServer(input)
+	defer ts.Close()
+
+	// Update our securityCredURL to point at our local test server.
+	originalSecurityCredURL := securityCredURL
+	securityCredURL = strings.Replace(securityCredURL, "http://100.100.100.200", ts.URL, -1)
+	defer func() {
+		securityCredURL = originalSecurityCredURL
+	}()
+
+	_, err := NewInstanceMetadataProvider().Retrieve()
+	assert.NotNil(t, err)
+	assert.Equal(t, expected, err.Error())
+}
+
+func TestInstanceMetadataProvider_Retrieve_Fail6(t *testing.T) {
+	test(t, `{}`, "AccessKeyId not in map")
+	test(t, `{"AccessKeyId":true}`,
+		"AccessKeyId is not a string in map")
+	test(t, `{"AccessKeyId":"access key id"}`,
+		"AccessKeySecret not in map")
+	test(t, `{"AccessKeyId":"access key id", "AccessKeySecret":true}`,
+		"AccessKeySecret is not a string in map")
+	test(t, `{"AccessKeyId":"access key id", "AccessKeySecret":"secret"}`,
+		"SecurityToken not in map")
+	test(t, `{"AccessKeyId":"access key id", "AccessKeySecret":"secret","SecurityToken":true}`,
+		"SecurityToken is not a string in map")
 }