Merge tag 'v2.0.0' into develop
更高单元测试, 修改了大量的bug, 可以投入生产
This commit is contained in:
commit
49d86f6d31
2
base.go
2
base.go
|
@ -37,12 +37,10 @@ func buildBodyRequest(wf *Workflow) *http.Request {
|
|||
contentType = wf.Body.ContentType()
|
||||
} else {
|
||||
contentType = ""
|
||||
if contentType == "" {
|
||||
if wf.Method == "POST" || wf.Method == "PUT" || wf.Method == "PATCH" {
|
||||
contentType = TypeURLENCODED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
req.Header.Set(HeaderKeyContentType, contentType)
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,9 +3,11 @@ module requests
|
|||
go 1.12
|
||||
|
||||
require (
|
||||
474420502.top/eson/gjson v1.1.3
|
||||
github.com/474420502/gjson v1.1.3
|
||||
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 // indirect
|
||||
github.com/tidwall/match v1.0.1 // indirect
|
||||
golang.org/x/net v0.0.0-20190902185345-cdfb69ac37fc6fa907650654115ebebb3aae2087
|
||||
golang.org/x/net v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
||||
replace golang.org/x/net => github.com/golang/net v0.0.0-20190902185345-cdfb69ac37fc6fa907650654115ebebb3aae2087
|
||||
|
|
14
go.sum
14
go.sum
|
@ -1,11 +1,11 @@
|
|||
474420502.top/eson/gjson v1.1.3 h1:SDeD1/SWm1YknuokcPww8ZmsOOguQqFAYLWnQTMMX98=
|
||||
474420502.top/eson/gjson v1.1.3/go.mod h1:95mdr7XPHsGvsGZj/FeQ+iT7mggI6LKc3JT/ZnveebI=
|
||||
github.com/474420502/gjson v1.1.3 h1:rQxKNSFS8bM5iVVKKb9EHY1SS2k+EhzVNUXe2xSGn8o=
|
||||
github.com/474420502/gjson v1.1.3/go.mod h1:mdAOevjPYIFWOE8CpejPHwoJCz96oNnuwhjhrAVeKaY=
|
||||
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2 h1:aZtFdDNWY/yH86JPR2WX/PN63635VsE/f/nXNPAbYxY=
|
||||
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/golang/net v0.0.0-20190902185345-cdfb69ac37fc6fa907650654115ebebb3aae2087 h1:haK1T12C0CO79KUdu+ZzLL9+l9BwM9PRkd2/mQqdg8E=
|
||||
github.com/golang/net v0.0.0-20190902185345-cdfb69ac37fc6fa907650654115ebebb3aae2087/go.mod h1:98y8FxUyMjTdJ5eOj/8vzuiVO14/dkJ98NYhEPG8QGY=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
29
init_test.go
Normal file
29
init_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package requests
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/elazarl/goproxy"
|
||||
)
|
||||
|
||||
const ProxyAddress = "localhost:58080"
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
||||
go func() {
|
||||
proxy := goproxy.NewProxyHttpServer()
|
||||
proxy.Verbose = true
|
||||
http.ListenAndServe(ProxyAddress, proxy)
|
||||
}()
|
||||
|
||||
cmd := exec.Command("/bin/bash", "-c", "docker ps | grep httpbin")
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Println("recommend 1. docker run -p 80:80 kennethreitz/httpbin \n2. echo \"127.0.0.1 httpbin.org\" >> /etc/hosts")
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
14
multipart.go
14
multipart.go
|
@ -35,6 +35,11 @@ func createMultipart(postParams IBody, params []interface{}) {
|
|||
param.FieldName = "file0"
|
||||
}
|
||||
writeFormUploadFile(mwriter, param)
|
||||
case UploadFile:
|
||||
if param.FieldName == "" {
|
||||
param.FieldName = "file0"
|
||||
}
|
||||
writeFormUploadFile(mwriter, ¶m)
|
||||
case []*UploadFile:
|
||||
for i, p := range param {
|
||||
if p.FieldName == "" {
|
||||
|
@ -42,6 +47,13 @@ func createMultipart(postParams IBody, params []interface{}) {
|
|||
}
|
||||
writeFormUploadFile(mwriter, p)
|
||||
}
|
||||
case []UploadFile:
|
||||
for i, p := range param {
|
||||
if p.FieldName == "" {
|
||||
p.FieldName = "file" + strconv.Itoa(i)
|
||||
}
|
||||
writeFormUploadFile(mwriter, &p)
|
||||
}
|
||||
case string:
|
||||
uploadFiles, err := UploadFileFromGlob(param)
|
||||
if err != nil {
|
||||
|
@ -63,7 +75,7 @@ func createMultipart(postParams IBody, params []interface{}) {
|
|||
} else {
|
||||
for ii, p := range uploadFiles {
|
||||
if p.FieldName == "" {
|
||||
p.FieldName = "file" + strconv.Itoa(ii) + "_" + strconv.Itoa(i)
|
||||
p.FieldName = "file" + strconv.Itoa(i) + "_" + strconv.Itoa(ii)
|
||||
}
|
||||
writeFormUploadFile(mwriter, p)
|
||||
}
|
||||
|
|
25
response.go
25
response.go
|
@ -16,7 +16,7 @@ type Response struct {
|
|||
}
|
||||
|
||||
// FromHTTPResponse 生成Response 从标准http.Response
|
||||
func FromHTTPResponse(resp *http.Response, IsDecompressNoAccept bool) (*Response, error) {
|
||||
func FromHTTPResponse(resp *http.Response, isDecompressNoAccept bool) (*Response, error) {
|
||||
var err error
|
||||
// 复制response 返回内容 并且测试是否有解压的需求
|
||||
srcbuf, err := ioutil.ReadAll(resp.Body)
|
||||
|
@ -27,8 +27,7 @@ func FromHTTPResponse(resp *http.Response, IsDecompressNoAccept bool) (*Response
|
|||
|
||||
content := ""
|
||||
|
||||
if IsDecompressNoAccept {
|
||||
|
||||
if isDecompressNoAccept { // 在某个已经遗忘的网页测试过, 为了兼容 Python requests
|
||||
srcReader := bytes.NewReader(srcbuf)
|
||||
var reader io.ReadCloser
|
||||
if reader, err = gzip.NewReader(srcReader); err == nil {
|
||||
|
@ -65,3 +64,23 @@ func (gresp *Response) Content() string {
|
|||
func (gresp *Response) GetSrcResponse() *http.Response {
|
||||
return gresp.readResponse
|
||||
}
|
||||
|
||||
// GetStatue 获取Statue String
|
||||
func (gresp *Response) GetStatue() string {
|
||||
return gresp.readResponse.Status
|
||||
}
|
||||
|
||||
// GetStatueCode 获取Statue int
|
||||
func (gresp *Response) GetStatueCode() int {
|
||||
return gresp.readResponse.StatusCode
|
||||
}
|
||||
|
||||
// GetHeader Header map[string][]string
|
||||
func (gresp *Response) GetHeader() http.Header {
|
||||
return gresp.readResponse.Header
|
||||
}
|
||||
|
||||
// GetContentLength 获取Content的内容长度, 如果存在 IsDecompressNoAccept 可能是压缩级别的长度, 非GetContent长度
|
||||
func (gresp *Response) GetContentLength() int64 {
|
||||
return gresp.readResponse.ContentLength
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
"474420502.top/eson/gjson"
|
||||
"github.com/474420502/gjson"
|
||||
)
|
||||
|
||||
func TestFromHTTPResponse(t *testing.T) {
|
||||
|
@ -31,9 +31,21 @@ func TestFromHTTPResponse(t *testing.T) {
|
|||
if len(resp.GetSrcResponse().Header) == 0 {
|
||||
t.Error("esp.GetSrcResponse().Header == nil")
|
||||
}
|
||||
|
||||
if resp.GetStatue() != "200 OK" || resp.GetStatueCode() != 200 {
|
||||
t.Error(" resp.GetStatue() != 200 OK")
|
||||
}
|
||||
|
||||
if len(resp.GetHeader()["Content-Length"]) != 1 {
|
||||
t.Error("resp.GetHeader() is error ?")
|
||||
}
|
||||
|
||||
if int64(len(resp.Content())) != resp.GetContentLength() {
|
||||
t.Error("content len is not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseGzipZip(t *testing.T) {
|
||||
func TestResponseDeflate(t *testing.T) {
|
||||
ses := NewSession()
|
||||
if wf := ses.Get("http://httpbin.org/get"); wf != nil {
|
||||
wf.AddHeader("accept-encoding", "deflate")
|
||||
|
@ -41,7 +53,9 @@ func TestResponseGzipZip(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Error(resp.Content())
|
||||
if gjson.Get(resp.Content(), "headers.Accept-Encoding").String() != "deflate" {
|
||||
t.Error("Accept-Encoding != deflate ?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
session.go
28
session.go
|
@ -78,7 +78,7 @@ type IBody interface {
|
|||
ContentType() string
|
||||
// AppendContent
|
||||
AddContentType(ct string)
|
||||
// SetPrefix 设置 Prefix; 唯一前缀
|
||||
// SetPrefix 设置 Prefix; 唯一前缀; 就是ContentType的第一个, ContentType(Prefix);ContentType;ContentType
|
||||
SetPrefix(ct string)
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ const (
|
|||
// TypeStream application/octet-stream 只能提交一个二进制流, 很少用
|
||||
TypeStream = "application/octet-stream"
|
||||
|
||||
// TypeFormData 类型
|
||||
// TypeFormData 类型 Upload File 支持path(string) 自动转换成UploadFile
|
||||
TypeFormData = "multipart/form-data"
|
||||
|
||||
// TypeMixed Mixed类型
|
||||
|
@ -161,7 +161,7 @@ const (
|
|||
// CDialTimeout 一个Connect过程的Timeout
|
||||
CDialTimeout // 支持time.Duration 和 int(秒为单位)
|
||||
|
||||
// CKeepAlives 默认不KeepAlives, 容易被一直KeepAlives 没关闭链接
|
||||
// CKeepAlives 默认KeepAlives false, 如果默认为true容易被一直KeepAlives, 没关闭链接
|
||||
CKeepAlives
|
||||
|
||||
// CProxy 代理链接
|
||||
|
@ -176,12 +176,12 @@ const (
|
|||
// CTLS 帐号认证
|
||||
CTLS // user pwd
|
||||
|
||||
// CCookiejar 持久化 CookieJar
|
||||
CCookiejar // true or false ; default = true
|
||||
// CIsWithCookiejar 持久化 CookieJar true or false ; default = true
|
||||
CIsWithCookiejar
|
||||
|
||||
// CDecompressNoAccept 解压 当response header 不存在 Accept-Encoding
|
||||
// CIsDecompressNoAccept 解压 当response header 不存在 Accept-Encoding
|
||||
// 很多特殊情景会不返回Accept-Encoding: Gzip. 如 不按照标准的网站
|
||||
CDecompressNoAccept
|
||||
CIsDecompressNoAccept
|
||||
)
|
||||
|
||||
// NewSession 创建Session
|
||||
|
@ -222,11 +222,12 @@ func (ses *Session) SetConfig(typeConfig TypeConfig, values interface{}) {
|
|||
}
|
||||
case CDialTimeout:
|
||||
// TODO: CDialTimeout CRequestTimeout 与 细节
|
||||
case CDecompressNoAccept:
|
||||
case CIsDecompressNoAccept:
|
||||
ses.Is.isDecompressNoAccept = values.(bool)
|
||||
case CKeepAlives:
|
||||
// println(ses.transport.DisableKeepAlives)
|
||||
ses.transport.DisableKeepAlives = !values.(bool)
|
||||
case CCookiejar:
|
||||
case CIsWithCookiejar:
|
||||
v := values.(bool)
|
||||
if v {
|
||||
if ses.client.Jar == nil {
|
||||
|
@ -260,13 +261,13 @@ func (ses *Session) SetConfig(typeConfig TypeConfig, values interface{}) {
|
|||
switch v := values.(type) {
|
||||
case *BasicAuth:
|
||||
ses.auth.User = v.User
|
||||
ses.auth.User = v.Password
|
||||
ses.auth.Password = v.Password
|
||||
case BasicAuth:
|
||||
ses.auth.User = v.User
|
||||
ses.auth.User = v.Password
|
||||
ses.auth.Password = v.Password
|
||||
case []string:
|
||||
ses.auth.User = v[0]
|
||||
ses.auth.User = v[1]
|
||||
ses.auth.Password = v[1]
|
||||
case nil:
|
||||
ses.auth = nil
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ func (ses *Session) GetQuery() url.Values {
|
|||
return ses.Query
|
||||
}
|
||||
|
||||
// SetHeader 设置set Header的值
|
||||
// SetHeader 设置set Header的值, 必须符合规范 HaHa -> Haha 如果真要HaHa,只能这样 Ha-Ha
|
||||
func (ses *Session) SetHeader(header http.Header) {
|
||||
ses.Header = header
|
||||
}
|
||||
|
@ -312,6 +313,7 @@ func (ses *Session) DelCookies(u *url.URL, name string) {
|
|||
for _, c := range cookies {
|
||||
if c.Name == name {
|
||||
c.MaxAge = -1
|
||||
break
|
||||
}
|
||||
}
|
||||
ses.SetCookies(u, cookies)
|
||||
|
|
176
session_test.go
176
session_test.go
|
@ -1,15 +1,15 @@
|
|||
package requests
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
"time"
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
||||
}
|
||||
"github.com/474420502/gjson"
|
||||
)
|
||||
|
||||
func TestNewSession(t *testing.T) {
|
||||
ses := NewSession()
|
||||
|
@ -297,7 +297,7 @@ func TestSession_SetConfig(t *testing.T) {
|
|||
|
||||
{
|
||||
name: "test proxy",
|
||||
args: args{typeConfig: CProxy, values: "http://474420502.top:7070"},
|
||||
args: args{typeConfig: CProxy, values: "http://" + ProxyAddress},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
@ -379,3 +379,167 @@ func TestSession_Header(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSession_ConfigEx(t *testing.T) {
|
||||
ses := NewSession()
|
||||
ses.SetConfig(CRequestTimeout, time.Microsecond)
|
||||
resp, err := ses.Get("http://httpbin.org/get").Execute()
|
||||
if err == nil {
|
||||
t.Error(resp)
|
||||
} else {
|
||||
if strings.LastIndex(err.Error(), "Client.Timeout exceeded while awaiting headers") < 0 {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
ses.SetConfig(CRequestTimeout, float32(0.0000001))
|
||||
resp, err = ses.Get("http://httpbin.org/get").Execute()
|
||||
if err == nil {
|
||||
t.Error(resp)
|
||||
} else {
|
||||
if strings.LastIndex(err.Error(), "Client.Timeout exceeded while awaiting headers") < 0 {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
ses.SetConfig(CKeepAlives, true)
|
||||
ses.SetConfig(CRequestTimeout, int64(5))
|
||||
// jar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
u, err := url.Parse("http://httpbin.org")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
// jar.SetCookies(u, []*http.Cookie{&http.Cookie{Name: "Request", Value: "Cookiejar"}})
|
||||
ses.SetConfig(CIsWithCookiejar, false)
|
||||
ses.SetConfig(CIsWithCookiejar, true)
|
||||
ses.SetCookies(u, []*http.Cookie{&http.Cookie{Name: "Request", Value: "Cookiejar"}, &http.Cookie{Name: "eson", Value: "bad"}})
|
||||
resp, err = ses.Get("http://httpbin.org/get").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "headers.Cookie").String() != "Request=Cookiejar; eson=bad" {
|
||||
t.Error(resp.Content())
|
||||
}
|
||||
|
||||
if resp.GetSrcResponse().Header["Connection"][0] != "keep-alive" {
|
||||
t.Error("CKeepAlive is error")
|
||||
}
|
||||
}
|
||||
|
||||
ses.SetConfig(CProxy, nil)
|
||||
if u, err := url.Parse("http://" + ProxyAddress); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
ses.SetConfig(CProxy, u)
|
||||
}
|
||||
|
||||
resp, err = ses.Get("http://httpbin.org/get").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ses.DelCookies(u, "eson")
|
||||
resp, err = ses.Get("http://httpbin.org/cookies").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cookies := ses.GetCookies(u)
|
||||
if len(cookies) != 1 && cookies[0].String() != "Request=Cookiejar" {
|
||||
t.Error("cookies del get error please check it")
|
||||
}
|
||||
|
||||
ses.ClearCookies()
|
||||
resp, err = ses.Get("http://httpbin.org/cookies").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if gjson.Get(resp.Content(), "cookies").String() != "{}" {
|
||||
t.Error(resp.Content())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSession_SetQuery(t *testing.T) {
|
||||
ses := NewSession()
|
||||
ses.SetQuery(url.Values{"query": []string{"a", "b"}})
|
||||
resp, err := ses.Get("http://httpbin.org/get").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
query := gjson.Get(resp.Content(), "args.query").Array()
|
||||
for _, q := range query {
|
||||
if !(q.String() == "a" || q.String() == "b") {
|
||||
t.Error("query error, ", resp.Content())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSession_SetHeader(t *testing.T) {
|
||||
ses := NewSession()
|
||||
var header http.Header
|
||||
header = make(http.Header)
|
||||
header["xx-xx"] = []string{"Header"}
|
||||
ses.SetHeader(header)
|
||||
|
||||
resp, err := ses.Get("http://httpbin.org/headers").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "headers.Xx-Xx").String() != "Header" {
|
||||
t.Error("Xx-Xx is not exists", resp.Content())
|
||||
}
|
||||
|
||||
if ses.GetHeader()["xx-xx"][0] != "Header" {
|
||||
t.Error("header error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSession_SetBasicAuth(t *testing.T) {
|
||||
ses := NewSession()
|
||||
ses.SetConfig(CBasicAuth, &BasicAuth{User: "eson", Password: "123456"})
|
||||
resp, err := ses.Get("http://httpbin.org/basic-auth/eson/123456").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if resp.GetSrcResponse().StatusCode != 200 {
|
||||
t.Error("code != 200, code = ", resp.GetStatue())
|
||||
}
|
||||
|
||||
ses.SetConfig(CBasicAuth, BasicAuth{User: "eson", Password: "12345"})
|
||||
resp, err = ses.Get("http://httpbin.org/basic-auth/eson/123456").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if resp.GetSrcResponse().StatusCode != 401 {
|
||||
t.Error("code != 401, code = ", resp.GetStatue())
|
||||
}
|
||||
|
||||
resp, err = ses.Get("http://httpbin.org/basic-auth/eson/123456").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if resp.GetSrcResponse().StatusCode != 401 {
|
||||
t.Error("code != 401, code = ", resp.GetStatue())
|
||||
}
|
||||
|
||||
ses.SetConfig(CBasicAuth, []string{"son", "123456"})
|
||||
resp, err = ses.Get("http://httpbin.org/basic-auth/eson/123456").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if resp.GetSrcResponse().StatusCode != 401 {
|
||||
t.Error("code != 401, code = ", resp.GetStatue())
|
||||
}
|
||||
|
||||
ses.SetConfig(CBasicAuth, nil)
|
||||
resp, err = ses.Get("http://httpbin.org/basic-auth/eson/123456").Execute()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if resp.GetSrcResponse().StatusCode != 401 {
|
||||
t.Error("code != 401, code = ", resp.GetStatue())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,51 @@ type UploadFile struct {
|
|||
FileReaderCloser io.ReadCloser
|
||||
}
|
||||
|
||||
// SetFileName 设置FileName属性
|
||||
func (ufile *UploadFile) SetFileName(filename string) {
|
||||
ufile.FileName = filename
|
||||
}
|
||||
|
||||
// GetFileName 设置FileName属性
|
||||
func (ufile *UploadFile) GetFileName() string {
|
||||
return ufile.FileName
|
||||
}
|
||||
|
||||
// SetFileReaderCloser 设置FileName属性
|
||||
func (ufile *UploadFile) SetFileReaderCloser(readerCloser io.ReadCloser) {
|
||||
ufile.FileReaderCloser = readerCloser
|
||||
}
|
||||
|
||||
// SetFileReaderCloserFromFile 设置FileName属性
|
||||
func (ufile *UploadFile) SetFileReaderCloserFromFile(filename string) error {
|
||||
fd, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ufile.SetFileReaderCloser(fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFileReaderCloser 设置FileName属性
|
||||
func (ufile *UploadFile) GetFileReaderCloser() io.ReadCloser {
|
||||
return ufile.FileReaderCloser
|
||||
}
|
||||
|
||||
// SetFieldName 设置FileName属性
|
||||
func (ufile *UploadFile) SetFieldName(fieldname string) {
|
||||
ufile.FieldName = fieldname
|
||||
}
|
||||
|
||||
// GetFieldName 设置FileName属性
|
||||
func (ufile *UploadFile) GetFieldName() string {
|
||||
return ufile.FieldName
|
||||
}
|
||||
|
||||
// NewUploadFile 创建一个空的UploadFile, 必须设置 FileName FieldName FileReaderCloser 三个属性
|
||||
func NewUploadFile() *UploadFile {
|
||||
return &UploadFile{}
|
||||
}
|
||||
|
||||
// UploadFileFromPath 从本地文件获取上传文件
|
||||
func UploadFileFromPath(fileName string) (*UploadFile, error) {
|
||||
fd, err := os.Open(fileName)
|
||||
|
|
107
upload_file_test.go
Normal file
107
upload_file_test.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
package requests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/474420502/gjson"
|
||||
)
|
||||
|
||||
func TestUploadFile(t *testing.T) {
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
|
||||
ses := NewSession()
|
||||
wf := ses.Put("http://httpbin.org/put")
|
||||
|
||||
ufile, err := UploadFileFromPath("tests/json.file")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
wf.SetBodyAuto(ufile, TypeFormData)
|
||||
resp, _ := wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
ses = NewSession()
|
||||
wf = ses.Patch("http://httpbin.org/patch")
|
||||
|
||||
wf.SetBodyAuto("tests/json.file", TypeFormData)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
ses = NewSession()
|
||||
wf = ses.Delete("http://httpbin.org/delete")
|
||||
ufile = NewUploadFile()
|
||||
ufile.SetFileName("MyFile")
|
||||
ufile.SetFieldName("MyField")
|
||||
ufile.SetFileReaderCloserFromFile("tests/json.file")
|
||||
wf.SetBodyAuto(ufile)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["MyField"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
// ses = NewSession()
|
||||
// wf = ses.Put("http://httpbin.org/put")
|
||||
|
||||
ufile.SetFileReaderCloserFromFile("tests/json.file")
|
||||
wf.SetBodyAuto(*ufile)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["MyField"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
// ses = NewSession()
|
||||
// wf = ses.Put("http://httpbin.org/put")
|
||||
|
||||
ufile = NewUploadFile()
|
||||
ufile.SetFileName("MyFile")
|
||||
ufile.SetFileReaderCloserFromFile("tests/json.file")
|
||||
wf.SetBodyAuto(ufile)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
ufile.SetFileReaderCloserFromFile("tests/json.file")
|
||||
wf.SetBodyAuto(*ufile)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
var ufileList []*UploadFile
|
||||
ufile, err = UploadFileFromPath("tests/json.file")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ufileList = append(ufileList, ufile)
|
||||
ufile, err = UploadFileFromPath("tests/learn.js")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ufileList = append(ufileList, ufile)
|
||||
wf.SetBodyAuto(ufileList)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file1"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
|
||||
if wf.GetBody().ContentType() != "" {
|
||||
t.Error("Body is not Clear")
|
||||
}
|
||||
|
||||
wf.SetBodyAuto([]string{"tests/learn.js", "tests/json.file"}, TypeFormData)
|
||||
resp, _ = wf.Execute()
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file1_0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
if _, ok := gjson.Get(resp.Content(), "files").Map()["file0_0"]; !ok {
|
||||
t.Error("file error", resp.Content())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
78
workflow.go
78
workflow.go
|
@ -21,7 +21,6 @@ type Workflow struct {
|
|||
func NewWorkflow(ses *Session, urlstr string) *Workflow {
|
||||
wf := &Workflow{}
|
||||
wf.SwitchSession(ses)
|
||||
|
||||
wf.SetRawURL(urlstr)
|
||||
|
||||
wf.Body = NewBody()
|
||||
|
@ -35,13 +34,13 @@ func (wf *Workflow) SwitchSession(ses *Session) {
|
|||
wf.session = ses
|
||||
}
|
||||
|
||||
// AddHeader 添加头信息 Get方法从Header参数上获取
|
||||
// AddHeader 添加头信息 Get方法从Header参数上获取 必须符合规范 HaHa -> Haha 如果真要HaHa,只能这样 Ha-Ha
|
||||
func (wf *Workflow) AddHeader(key, value string) *Workflow {
|
||||
wf.Header[key] = append(wf.Header[key], value)
|
||||
return wf
|
||||
}
|
||||
|
||||
// SetHeader 设置完全替换原有Header
|
||||
// SetHeader 设置完全替换原有Header 必须符合规范 HaHa -> Haha 如果真要HaHa,只能这样 Ha-Ha
|
||||
func (wf *Workflow) SetHeader(header http.Header) *Workflow {
|
||||
wf.Header = make(http.Header)
|
||||
for k, HValues := range header {
|
||||
|
@ -162,7 +161,7 @@ func (wf *Workflow) SetQuery(query url.Values) *Workflow {
|
|||
|
||||
var regexGetPath = regexp.MustCompile("/[^/]*")
|
||||
|
||||
// GetURLPath 获取Path参数
|
||||
// GetURLPath 获取Path参数 http://localhost/anything/user/pwd return [/anything /user /pwd]
|
||||
func (wf *Workflow) GetURLPath() []string {
|
||||
return regexGetPath.FindAllString(wf.ParsedURL.Path, -1)
|
||||
}
|
||||
|
@ -173,29 +172,33 @@ func (wf *Workflow) GetURLRawPath() string {
|
|||
}
|
||||
|
||||
// encodePath path格式每个item都必须以/开头
|
||||
// func encodePath(path []string) string {
|
||||
// rawpath := ""
|
||||
// for _, p := range path {
|
||||
// if p[0] != '/' {
|
||||
// p = "/" + p
|
||||
// }
|
||||
// rawpath += p
|
||||
// }
|
||||
// return rawpath
|
||||
// }
|
||||
func encodePath(path []string) string {
|
||||
rawpath := ""
|
||||
for _, p := range path {
|
||||
if p[0] != '/' {
|
||||
p = "/" + p
|
||||
}
|
||||
rawpath += p
|
||||
}
|
||||
return rawpath
|
||||
}
|
||||
|
||||
// // SetURLPath 设置Path参数
|
||||
// func (wf *Workflow) SetURLPath(path []string) *Workflow {
|
||||
// if path == nil {
|
||||
// return wf
|
||||
// }
|
||||
// wf.ParsedURL.Path = encodePath(path)
|
||||
// return wf
|
||||
// }
|
||||
// SetURLPath 设置Path参数 对应 GetURLPath
|
||||
func (wf *Workflow) SetURLPath(path []string) *Workflow {
|
||||
if path == nil {
|
||||
return wf
|
||||
}
|
||||
wf.ParsedURL.Path = encodePath(path)
|
||||
return wf
|
||||
}
|
||||
|
||||
// SetURLRawPath 设置Pa晚上参数
|
||||
// SetURLRawPath 设置 参数 eg. /get = http:// hostname + /get
|
||||
func (wf *Workflow) SetURLRawPath(path string) *Workflow {
|
||||
if path[0] != '/' {
|
||||
wf.ParsedURL.Path = "/" + path
|
||||
} else {
|
||||
wf.ParsedURL.Path = path
|
||||
}
|
||||
return wf
|
||||
}
|
||||
|
||||
|
@ -206,7 +209,7 @@ func (wf *Workflow) SetBody(body IBody) *Workflow {
|
|||
}
|
||||
|
||||
// GetBody 参数设置
|
||||
func (wf *Workflow) GetBody(body IBody) IBody {
|
||||
func (wf *Workflow) GetBody() IBody {
|
||||
return wf.Body
|
||||
}
|
||||
|
||||
|
@ -224,9 +227,10 @@ func (wf *Workflow) SetBodyAuto(params ...interface{}) *Workflow {
|
|||
|
||||
wf.Body.SetPrefix(defaultContentType)
|
||||
|
||||
if defaultContentType == TypeFormData {
|
||||
createMultipart(wf.Body, params)
|
||||
} else {
|
||||
switch defaultContentType {
|
||||
case TypeFormData:
|
||||
createMultipart(wf.Body, params) // 还存在 Mixed的可能
|
||||
default:
|
||||
var values url.Values
|
||||
switch param := params[0].(type) {
|
||||
case map[string]string:
|
||||
|
@ -242,10 +246,27 @@ func (wf *Workflow) SetBodyAuto(params ...interface{}) *Workflow {
|
|||
wf.Body.SetIOBody([]byte(param))
|
||||
case []byte:
|
||||
wf.Body.SetIOBody(param)
|
||||
|
||||
case *UploadFile:
|
||||
params = append(params, TypeFormData)
|
||||
wf.Body.SetPrefix(TypeFormData)
|
||||
createMultipart(wf.Body, params)
|
||||
case UploadFile:
|
||||
params = append(params, TypeFormData)
|
||||
wf.Body.SetPrefix(TypeFormData)
|
||||
createMultipart(wf.Body, params)
|
||||
case []*UploadFile:
|
||||
params = append(params, TypeFormData)
|
||||
wf.Body.SetPrefix(TypeFormData)
|
||||
createMultipart(wf.Body, params)
|
||||
case []UploadFile:
|
||||
params = append(params, TypeFormData)
|
||||
wf.Body.SetPrefix(TypeFormData)
|
||||
createMultipart(wf.Body, params)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return wf
|
||||
}
|
||||
|
||||
|
@ -312,5 +333,6 @@ func (wf *Workflow) Execute() (*Response, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
wf.Body = NewBody()
|
||||
return FromHTTPResponse(resp, wf.session.Is.isDecompressNoAccept)
|
||||
}
|
||||
|
|
248
workflow_test.go
248
workflow_test.go
|
@ -1,10 +1,13 @@
|
|||
package requests
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"474420502.top/eson/gjson"
|
||||
"github.com/474420502/gjson"
|
||||
)
|
||||
|
||||
func TestWorkflow(t *testing.T) {
|
||||
|
@ -57,4 +60,247 @@ func TestWorkflow(t *testing.T) {
|
|||
t.Error(resp.readContent)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestWorkflow_SetHeader(t *testing.T) {
|
||||
ses := NewSession()
|
||||
wf := ses.Get("http://httpbin.org/headers")
|
||||
var header http.Header
|
||||
header = make(http.Header)
|
||||
header["Eson"] = []string{"Bad"}
|
||||
header["HaHa"] = []string{"xixi"}
|
||||
wf.SetHeader(header)
|
||||
|
||||
resp, err := wf.Execute()
|
||||
if err == nil && gjson.Get(resp.Content(), "headers.Eson").String() != "Bad" {
|
||||
t.Error("wf header error", resp.Content())
|
||||
}
|
||||
|
||||
if err == nil && gjson.Get(resp.Content(), "headers.Haha").String() != "xixi" {
|
||||
t.Error("wf header error", resp.Content())
|
||||
}
|
||||
|
||||
// 输入不符合规范不 会自动转换
|
||||
if wf.GetHeader()["HaHa"][0] != "xixi" {
|
||||
t.Error("Header 错误")
|
||||
}
|
||||
|
||||
if len(ses.GetHeader()) != 0 {
|
||||
t.Error("session header should be zero")
|
||||
}
|
||||
|
||||
delete(header, "HaHa")
|
||||
ses.SetHeader(header)
|
||||
wf = ses.Get("http://httpbin.org/headers")
|
||||
wf.AddHeader("Hello", "Hehe")
|
||||
|
||||
resp, err = wf.Execute()
|
||||
if err != nil || gjson.Get(resp.Content(), "headers.Eson").String() != "Bad" {
|
||||
t.Error("wf header error", resp.Content())
|
||||
}
|
||||
|
||||
if err != nil || gjson.Get(resp.Content(), "headers.Hello").String() != "Hehe" {
|
||||
t.Error("wf header error", resp.Content())
|
||||
}
|
||||
|
||||
if len(wf.GetHeader()) != 1 || wf.GetHeader()["Hello"][0] != "Hehe" {
|
||||
t.Error("session header should be 1")
|
||||
}
|
||||
|
||||
cheader := wf.GetCombineHeader()
|
||||
if len(cheader) != 2 || cheader["Eson"][0] != "Bad" {
|
||||
t.Error("GetCombineHeader error")
|
||||
}
|
||||
|
||||
resp, err = wf.DelHeader("Hello").Execute()
|
||||
if err != nil {
|
||||
t.Error(err, resp.Content())
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "headers.Hello").Exists() {
|
||||
t.Error(" wf.DelHeader error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkflow_Cookies(t *testing.T) {
|
||||
ses := NewSession()
|
||||
u, err := url.Parse("http://httpbin.org")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ses.SetCookies(u, []*http.Cookie{&http.Cookie{Name: "Request", Value: "Cookiejar"}})
|
||||
wf := ses.Get("http://httpbin.org/cookies")
|
||||
wf.AddCookie(&http.Cookie{Name: "eson", Value: "Bad"})
|
||||
|
||||
resp, _ := wf.Execute()
|
||||
if gjson.Get(resp.Content(), "cookies.Request").String() != "Cookiejar" {
|
||||
t.Error(" wf.AddCookie error")
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "cookies.eson").String() != "Bad" {
|
||||
t.Error(" wf.AddCookie error")
|
||||
}
|
||||
|
||||
wf.DelCookie("eson")
|
||||
resp, _ = wf.Execute()
|
||||
if gjson.Get(resp.Content(), "cookies.Request").String() != "Cookiejar" {
|
||||
t.Error(" wf.AddCookie error")
|
||||
}
|
||||
if gjson.Get(resp.Content(), "cookies.eson").Exists() {
|
||||
t.Error(" wf.DelCookie error")
|
||||
}
|
||||
|
||||
wf.AddCookies([]*http.Cookie{&http.Cookie{Name: "A", Value: "AA"}, &http.Cookie{Name: "B", Value: "BB"}})
|
||||
|
||||
resp, _ = wf.Execute()
|
||||
if gjson.Get(resp.Content(), "cookies.Request").String() != "Cookiejar" {
|
||||
t.Error(" wf.AddCookie error")
|
||||
}
|
||||
if gjson.Get(resp.Content(), "cookies.A").String() != "AA" {
|
||||
t.Error(" wf.AddCookies error")
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "cookies.B").String() != "BB" {
|
||||
t.Error(" wf.AddCookies error")
|
||||
}
|
||||
|
||||
wf.DelCookie(&http.Cookie{Name: "A", Value: "AA"})
|
||||
resp, _ = wf.Execute()
|
||||
if gjson.Get(resp.Content(), "cookies.A").Exists() {
|
||||
t.Error(" wf.AddCookies error")
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "cookies.B").String() != "BB" {
|
||||
t.Error(" wf.AddCookies error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkflow_URL(t *testing.T) {
|
||||
ses := NewSession()
|
||||
wf := ses.Get("http://httpbin.org/")
|
||||
u, err := url.Parse("http://httpbin.org/get")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
wf.SetParsedURL(u)
|
||||
resp, _ := wf.Execute()
|
||||
if gjson.Get(resp.Content(), "url").String() != "http://httpbin.org/get" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
|
||||
if wf.GetParsedURL().String() != "http://httpbin.org/get" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
|
||||
wf = ses.Get("http://httpbin.org/")
|
||||
|
||||
resp, _ = wf.SetURLRawPath("/get").Execute()
|
||||
if gjson.Get(resp.Content(), "url").String() != "http://httpbin.org/get" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
|
||||
if wf.GetURLRawPath() != "/get" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
|
||||
resp, _ = wf.SetURLRawPath("anything/user/password").Execute()
|
||||
if gjson.Get(resp.Content(), "url").String() != "http://httpbin.org/anything/user/password" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
paths := wf.GetURLPath()
|
||||
if paths[0] != "/anything" || paths[1] != "/user" || paths[2] != "/password" {
|
||||
t.Error("wf.GetURLPath()", paths)
|
||||
}
|
||||
|
||||
wf = ses.Get("http://httpbin.org/")
|
||||
wf.SetURLPath(paths)
|
||||
if gjson.Get(resp.Content(), "url").String() != "http://httpbin.org/anything/user/password" {
|
||||
t.Error("SetParsedURL ", resp.Content())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkflow_Query(t *testing.T) {
|
||||
ses := NewSession()
|
||||
query := make(url.Values)
|
||||
query["session"] = []string{"true"}
|
||||
ses.SetQuery(query)
|
||||
wf := ses.Get("http://httpbin.org/get")
|
||||
wfquery := make(url.Values)
|
||||
wfquery["workflow"] = []string{"do", "to"}
|
||||
wf.SetQuery(wfquery)
|
||||
|
||||
resp, _ := wf.Execute()
|
||||
result := gjson.Get(resp.Content(), "args.workflow")
|
||||
|
||||
for _, r := range result.Array() {
|
||||
if !(r.String() == "to" || r.String() == "do") {
|
||||
t.Error("workflow SetQuery error")
|
||||
}
|
||||
}
|
||||
|
||||
if gjson.Get(resp.Content(), "args.session").String() != "true" {
|
||||
t.Error("session SetQuery error")
|
||||
}
|
||||
|
||||
if v, ok := wf.GetQuery()["workflow"]; ok {
|
||||
sort.Slice(v, func(i, j int) bool {
|
||||
if v[i] > v[j] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if !(v[0] == "to" && v[1] == "do") && len(v) != 2 {
|
||||
t.Error("workflow GetQuery", v)
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := wf.GetQuery()["session"]; ok {
|
||||
if v[0] != "true" && len(v) != 1 {
|
||||
t.Error("workflow error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkflow_Body(t *testing.T) {
|
||||
ses := NewSession()
|
||||
wf := ses.Post("http://httpbin.org/post")
|
||||
body := NewBody()
|
||||
body.SetIOBody("a=1&b=2")
|
||||
wf.SetBody(body)
|
||||
resp, _ := wf.Execute()
|
||||
form := gjson.Get(resp.Content(), "form").Map()
|
||||
if v, ok := form["a"]; ok {
|
||||
if v.String() != "1" {
|
||||
t.Error(v)
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := form["b"]; ok {
|
||||
if v.String() != "2" {
|
||||
t.Error(v)
|
||||
}
|
||||
}
|
||||
|
||||
body.SetPrefix(TypeJSON)
|
||||
body.SetIOBody(`{"a": "1", "b": "2"}`)
|
||||
wf.SetBody(body)
|
||||
resp, _ = wf.Execute()
|
||||
json := gjson.Get(resp.Content(), "json").Map()
|
||||
if v, ok := json["a"]; ok {
|
||||
if v.String() != "1" {
|
||||
t.Error(v)
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := json["b"]; ok {
|
||||
if v.String() != "2" {
|
||||
t.Error(v)
|
||||
}
|
||||
}
|
||||
|
||||
// body.SetPrefix(TypeXML)
|
||||
// body.SetIOBody(`<root><a>1</a><b>2</b></root>`)
|
||||
// wf.SetBody(body)
|
||||
// resp, _ = wf.Execute()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user