Compare commits

...

10 Commits

Author SHA1 Message Date
Jackson Tian 6f53c070b4 Update README-CN.md 2023-04-26 11:20:13 +08:00
Jackson Tian 02f393be3f Delete .travis.yml 2023-03-23 15:12:14 +08:00
nanhe c87ce79386 support port for url request 2023-03-23 15:01:26 +08:00
nanhe b9ace42a5b feat: return description and accessDeniedDetail in error info 2022-10-20 15:56:55 +08:00
nanhe 3a75a83be1 support when statusCode is *int 2022-06-20 20:19:19 +08:00
nanhe af66437067 support statusCode in data for SDKError 2022-06-14 16:16:13 +08:00
nanhe e0a739a681 add Action 2022-06-14 16:16:13 +08:00
ziggy d9ff2bfbeb add StatusCode for SDK Error
Co-authored-by: zigang.wang <zigang.wang@alibaba-inc.com>
2021-07-23 13:54:08 +08:00
peze fc13b6ebee fix the big number unmarshal error 2021-05-19 09:42:26 +08:00
wb-wzc505509 6355725204 modify Convert 2021-01-26 17:34:04 +08:00
8 changed files with 1430 additions and 48 deletions
+35
View File
@@ -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
View File
@@ -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)
+3 -3
View File
@@ -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>
[![Go CI](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml/badge.svg)](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
该项目用于支持TEA OpenAPI DSL。它是http请求的底层库.
该项目用于支持 Darabonba OpenAPI DSL。它是http请求的底层库.
## 许可证
[Apache-2.0](/LICENSE)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
+2
View File
@@ -4,5 +4,7 @@ go 1.14
require (
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68
github.com/json-iterator/go v1.1.10
github.com/modern-go/reflect2 v1.0.1
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
)
+333
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+63 -11
View File
@@ -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 := json.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)
+114 -10
View File
@@ -141,12 +141,14 @@ func TestConvert(t *testing.T) {
func TestConvertType(t *testing.T) {
in := map[string]interface{}{
"key": 123,
"key": 123,
"body": []byte("test"),
}
out := new(test)
err := Convert(in, &out)
utils.AssertNotNil(t, err)
utils.AssertEqual(t, "json: cannot unmarshal number into Go struct field test.key of type string", err.Error())
utils.AssertNil(t, err)
utils.AssertEqual(t, "123", out.Key)
utils.AssertEqual(t, "test", string(out.Body))
}
func TestRuntimeObject(t *testing.T) {
@@ -159,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) {
@@ -248,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",
@@ -332,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))
@@ -475,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) {