Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e717c11b4a | |||
| 02f393be3f | |||
| c87ce79386 | |||
| b9ace42a5b | |||
| 3a75a83be1 | |||
| af66437067 | |||
| e0a739a681 | |||
| d9ff2bfbeb | |||
| fc13b6ebee |
@@ -0,0 +1,35 @@
|
||||
name: Go CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.13, 1.14, 1.15]
|
||||
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build Tea
|
||||
run: go build ./tea
|
||||
- name: Build Util
|
||||
run: go build ./utils
|
||||
|
||||
- name: Test
|
||||
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./tea/... ./utils/...
|
||||
|
||||
- name: CodeCov
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
|
||||
branches: # build only on these branches
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- export GO111MODULE=on
|
||||
|
||||
notifications:
|
||||
webhooks: https://oapi.dingtalk.com/robot/send?access_token=096ed387df243a6d60835aadeccc47165f3813bc7cb81cdd0cfeadfd28e3acc1
|
||||
email: false
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
script:
|
||||
- go mod tidy
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic ./tea/... ./utils/...
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
<a href="https://badge.fury.io/gh/alibabacloud-go%2Ftea"><img src="https://badge.fury.io/gh/alibabacloud-go%2Ftea.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://codecov.io/gh/alibabacloud-go/tea"><img src="https://codecov.io/gh/alibabacloud-go/tea/branch/master/graph/badge.svg" alt="codecov"></a>
|
||||
<a href="https://travis-ci.org/alibabacloud-go/tea"><img src="https://travis-ci.org/alibabacloud-go/tea.svg?branch=master" alt="Travis Build Status"></a>
|
||||
[](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
|
||||
|
||||
This project is used for support TEA OpenAPI DSL. It's a low-level library for http request.
|
||||
This project is used for support Darabonba OpenAPI DSL. It's a low-level library for http request.
|
||||
|
||||
## License
|
||||
[Apache-2.0](/LICENSE)
|
||||
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
|
||||
+63
-11
@@ -69,11 +69,14 @@ type Response struct {
|
||||
|
||||
// SDKError struct is used save error code and message
|
||||
type SDKError struct {
|
||||
Code *string
|
||||
Message *string
|
||||
Data *string
|
||||
Stack *string
|
||||
errMsg *string
|
||||
Code *string
|
||||
StatusCode *int
|
||||
Message *string
|
||||
Data *string
|
||||
Stack *string
|
||||
errMsg *string
|
||||
Description *string
|
||||
AccessDeniedDetail map[string]interface{}
|
||||
}
|
||||
|
||||
// RuntimeObject is used for converting http configuration
|
||||
@@ -180,10 +183,54 @@ func NewSDKError(obj map[string]interface{}) *SDKError {
|
||||
if obj["message"] != nil {
|
||||
err.Message = String(obj["message"].(string))
|
||||
}
|
||||
if obj["description"] != nil {
|
||||
err.Description = String(obj["description"].(string))
|
||||
}
|
||||
if detail := obj["accessDeniedDetail"]; detail != nil {
|
||||
r := reflect.ValueOf(detail)
|
||||
if r.Kind().String() == "map" {
|
||||
res := make(map[string]interface{})
|
||||
tmp := r.MapKeys()
|
||||
for _, key := range tmp {
|
||||
res[key.String()] = r.MapIndex(key).Interface()
|
||||
}
|
||||
err.AccessDeniedDetail = res
|
||||
}
|
||||
}
|
||||
if data := obj["data"]; data != nil {
|
||||
r := reflect.ValueOf(data)
|
||||
if r.Kind().String() == "map" {
|
||||
res := make(map[string]interface{})
|
||||
tmp := r.MapKeys()
|
||||
for _, key := range tmp {
|
||||
res[key.String()] = r.MapIndex(key).Interface()
|
||||
}
|
||||
if statusCode := res["statusCode"]; statusCode != nil {
|
||||
if code, ok := statusCode.(int); ok {
|
||||
err.StatusCode = Int(code)
|
||||
} else if tmp, ok := statusCode.(string); ok {
|
||||
code, err_ := strconv.Atoi(tmp)
|
||||
if err_ == nil {
|
||||
err.StatusCode = Int(code)
|
||||
}
|
||||
} else if code, ok := statusCode.(*int); ok {
|
||||
err.StatusCode = code
|
||||
}
|
||||
}
|
||||
}
|
||||
byt, _ := json.Marshal(data)
|
||||
err.Data = String(string(byt))
|
||||
}
|
||||
|
||||
if statusCode, ok := obj["statusCode"].(int); ok {
|
||||
err.StatusCode = Int(statusCode)
|
||||
} else if status, ok := obj["statusCode"].(string); ok {
|
||||
statusCode, err_ := strconv.Atoi(status)
|
||||
if err_ == nil {
|
||||
err.StatusCode = Int(statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -194,8 +241,8 @@ func (err *SDKError) SetErrMsg(msg string) {
|
||||
|
||||
func (err *SDKError) Error() string {
|
||||
if err.errMsg == nil {
|
||||
str := fmt.Sprintf("SDKError:\n Code: %s\n Message: %s\n Data: %s\n",
|
||||
StringValue(err.Code), StringValue(err.Message), StringValue(err.Data))
|
||||
str := fmt.Sprintf("SDKError:\n StatusCode: %d\n Code: %s\n Message: %s\n Data: %s\n",
|
||||
IntValue(err.StatusCode), StringValue(err.Code), StringValue(err.Message), StringValue(err.Data))
|
||||
err.SetErrMsg(str)
|
||||
}
|
||||
return StringValue(err.errMsg)
|
||||
@@ -209,7 +256,9 @@ func (err *CastError) Error() string {
|
||||
// Convert is use convert map[string]interface object to struct
|
||||
func Convert(in interface{}, out interface{}) error {
|
||||
byt, _ := json.Marshal(in)
|
||||
err := jsonParser.Unmarshal(byt, out)
|
||||
decoder := jsonParser.NewDecoder(bytes.NewReader(byt))
|
||||
decoder.UseNumber()
|
||||
err := decoder.Decode(&out)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -273,6 +322,9 @@ func DoRequest(request *Request, requestRuntime map[string]interface{}) (respons
|
||||
|
||||
requestURL := ""
|
||||
request.Domain = request.Headers["host"]
|
||||
if request.Port != nil {
|
||||
request.Domain = String(fmt.Sprintf("%s:%d", StringValue(request.Domain), IntValue(request.Port)))
|
||||
}
|
||||
requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname))
|
||||
queryParams := request.Query
|
||||
// sort QueryParams by key
|
||||
@@ -765,10 +817,10 @@ func Retryable(err error) *bool {
|
||||
return Bool(false)
|
||||
}
|
||||
if realErr, ok := err.(*SDKError); ok {
|
||||
code, err := strconv.Atoi(StringValue(realErr.Code))
|
||||
if err != nil {
|
||||
return Bool(true)
|
||||
if realErr.StatusCode == nil {
|
||||
return Bool(false)
|
||||
}
|
||||
code := IntValue(realErr.StatusCode)
|
||||
return Bool(code >= http.StatusInternalServerError)
|
||||
}
|
||||
return Bool(true)
|
||||
|
||||
+121
-7
@@ -139,6 +139,18 @@ func TestConvert(t *testing.T) {
|
||||
utils.AssertEqual(t, "test", string(out.Body))
|
||||
}
|
||||
|
||||
func TestConvertType(t *testing.T) {
|
||||
in := map[string]interface{}{
|
||||
"key": 123,
|
||||
"body": []byte("test"),
|
||||
}
|
||||
out := new(test)
|
||||
err := Convert(in, &out)
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "123", out.Key)
|
||||
utils.AssertEqual(t, "test", string(out.Body))
|
||||
}
|
||||
|
||||
func TestRuntimeObject(t *testing.T) {
|
||||
runtimeobject := NewRuntimeObject(nil)
|
||||
utils.AssertNil(t, runtimeobject.IgnoreSSL)
|
||||
@@ -149,28 +161,94 @@ func TestRuntimeObject(t *testing.T) {
|
||||
|
||||
func TestSDKError(t *testing.T) {
|
||||
err := NewSDKError(map[string]interface{}{
|
||||
"code": "code",
|
||||
"message": "message",
|
||||
"code": "code",
|
||||
"statusCode": 404,
|
||||
"message": "message",
|
||||
"data": map[string]interface{}{
|
||||
"httpCode": "404",
|
||||
"requestId": "dfadfa32cgfdcasd4313",
|
||||
"hostId": "github.com/alibabacloud/tea",
|
||||
},
|
||||
"description": "description",
|
||||
"accessDeniedDetail": map[string]interface{}{
|
||||
"AuthAction": "ram:ListUsers",
|
||||
"AuthPrincipalType": "SubUser",
|
||||
"PolicyType": "ResourceGroupLevelIdentityBassdPolicy",
|
||||
"NoPermissionType": "ImplicitDeny",
|
||||
"UserId": 123,
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, "SDKError:\n Code: code\n Message: message\n Data: {\"hostId\":\"github.com/alibabacloud/tea\",\"httpCode\":\"404\",\"requestId\":\"dfadfa32cgfdcasd4313\"}\n", err.Error())
|
||||
utils.AssertEqual(t, "SDKError:\n StatusCode: 404\n Code: code\n Message: message\n Data: {\"hostId\":\"github.com/alibabacloud/tea\",\"httpCode\":\"404\",\"requestId\":\"dfadfa32cgfdcasd4313\"}\n", err.Error())
|
||||
|
||||
err.SetErrMsg("test")
|
||||
utils.AssertEqual(t, "test", err.Error())
|
||||
utils.AssertEqual(t, 404, *err.StatusCode)
|
||||
utils.AssertEqual(t, "description", *err.Description)
|
||||
utils.AssertEqual(t, "ImplicitDeny", err.AccessDeniedDetail["NoPermissionType"])
|
||||
utils.AssertEqual(t, 123, err.AccessDeniedDetail["UserId"])
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"statusCode": "404",
|
||||
"data": map[string]interface{}{
|
||||
"statusCode": 500,
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, 404, *err.StatusCode)
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"statusCode": 500,
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, 500, *err.StatusCode)
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"statusCode": Int(500),
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, 500, *err.StatusCode)
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"statusCode": "500",
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, 500, *err.StatusCode)
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"code": "code",
|
||||
"message": "message",
|
||||
"data": map[string]interface{}{
|
||||
"requestId": "dfadfa32cgfdcasd4313",
|
||||
},
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertNil(t, err.StatusCode)
|
||||
|
||||
err = NewSDKError(map[string]interface{}{
|
||||
"code": "code",
|
||||
"message": "message",
|
||||
"data": "string data",
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertNotNil(t, err.Data)
|
||||
utils.AssertNil(t, err.StatusCode)
|
||||
}
|
||||
|
||||
func TestSDKErrorCode404(t *testing.T) {
|
||||
err := NewSDKError(map[string]interface{}{
|
||||
"code": 404,
|
||||
"message": "message",
|
||||
"statusCode": 404,
|
||||
"code": "NOTFOUND",
|
||||
"message": "message",
|
||||
})
|
||||
utils.AssertNotNil(t, err)
|
||||
utils.AssertEqual(t, "SDKError:\n Code: 404\n Message: message\n Data: \n", err.Error())
|
||||
utils.AssertEqual(t, "SDKError:\n StatusCode: 404\n Code: NOTFOUND\n Message: message\n Data: \n", err.Error())
|
||||
}
|
||||
|
||||
func TestToObject(t *testing.T) {
|
||||
@@ -238,9 +316,11 @@ type Test struct {
|
||||
func TestToMap(t *testing.T) {
|
||||
in := map[string]*string{
|
||||
"tea": String("test"),
|
||||
"nil": nil,
|
||||
}
|
||||
result := ToMap(in)
|
||||
utils.AssertEqual(t, "test", result["tea"])
|
||||
utils.AssertNil(t, result["nil"])
|
||||
|
||||
validMap := map[string]interface{}{
|
||||
"valid": "test",
|
||||
@@ -322,9 +402,29 @@ func Test_Retryable(t *testing.T) {
|
||||
}
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, false, BoolValue(ifRetry))
|
||||
|
||||
errmsg["statusCode"] = 400
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, false, BoolValue(ifRetry))
|
||||
|
||||
errmsg["statusCode"] = "400"
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, false, BoolValue(ifRetry))
|
||||
|
||||
errmsg["statusCode"] = 500
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, true, BoolValue(ifRetry))
|
||||
|
||||
errmsg["code"] = "400"
|
||||
errmsg["statusCode"] = "500"
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, true, BoolValue(ifRetry))
|
||||
|
||||
errmsg["statusCode"] = "test"
|
||||
err = NewSDKError(errmsg)
|
||||
ifRetry = Retryable(err)
|
||||
utils.AssertEqual(t, false, BoolValue(ifRetry))
|
||||
@@ -465,6 +565,20 @@ func Test_DoRequest(t *testing.T) {
|
||||
resp, err = DoRequest(request, runtimeObj)
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "test", StringValue(resp.Headers["tea"]))
|
||||
|
||||
hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
utils.AssertEqual(t, "tea-cn-hangzhou.aliyuncs.com:1080", req.Host)
|
||||
return mockResponse(200, ``, errors.New("Internal error"))
|
||||
}
|
||||
}
|
||||
request.Pathname = String("/log")
|
||||
request.Protocol = String("http")
|
||||
request.Port = Int(1080)
|
||||
request.Headers["host"] = String("tea-cn-hangzhou.aliyuncs.com")
|
||||
resp, err = DoRequest(request, runtimeObj)
|
||||
utils.AssertNil(t, resp)
|
||||
utils.AssertEqual(t, `Internal error`, err.Error())
|
||||
}
|
||||
|
||||
func Test_DoRequestWithConcurrent(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user