我正在制作一个自动化的API测试套件。我想模拟实际的最终用户呼叫,并且不想使用req.Header.Add("Set-Cookie", Session)
。除了会话(未从服务器进行身份验证)以外,其他所有程序都工作正常,即使第一次测试运行是对仅通过成功登录(基本/承载)和会话才能继续的身份验证端点进行测试。
您如何跟踪从一个响应到下一个请求的会话?其中包括完整的源代码以及相关的输出和服务器日志。
在Postman中一切正常,但是如果我导出为Go代码并运行,则会遇到相同的问题。一定是带有跟踪会话的东西。
在请求设置中,我有:
cookie := res.Header.Get("Set-Cookie")
if len(cookie) > 0 {
Session = cookie
}
会话在响应中更新:
=== RUN TestAuthenticate
golang-api->TestAuthenticate: Testing endpoint /authenticate...
golang-api->TestAuthenticate: > No Authorization provided in header...
golang-api->TestAuthenticate: > Basic missing and bearer present in header...
golang-api->TestAuthenticate: > Bearer missing and basic present in header...
golang-api->TestAuthenticate: > Invalid Authorization Header (Bad Basic)...
golang-api->TestAuthenticate: > Invalid Authorization Header (Bad Bearer)...
golang-api->TestAuthenticate: > Invalid Authorization Header (Bad Basic & Bearer)...
golang-api->TestAuthenticate: > Valid Authorization Header (Good Basic & Bearer)...
golang-api->TestAuthenticate: SUCCESS Ok
--- PASS: TestAuthenticate (0.03s)
=== RUN TestBonus
golang-api->TestBonus: Testing endpoint /bonus...
golang-api->TestBonus: > No Basic Authorization provided in header...
golang-api->TestBonus: > Invalid Basic Authorization Header (Bad Basic)...
golang-api->TestBonus: > Valid Basic Authorization Header (Good Basic)...
golang-api->TestBonus: ERROR Expected Status Code 200 got 401 instead
Exiting on GET request http://10.11.2.148:8080/bonus ...
REQUEST: &{Method:GET URL:http://10.11.2.148:8080/bonus Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[User-Agent:[GoLang API Test/0.1.0] Cache-Control:[no-cache] Authorization:[Basic YXNoaXNoOmEyNkIpbl5BPyU2V2YhQXNKdw==]] Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false Host:10.11.2.148:8080 Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil> Response:<nil> ctx:<nil>}
RESPONSE: &{Status:401 Unauthorized StatusCode:401 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[X-Xss-Protection:[1; mode=block] Referrer-Policy:[same-origin] Set-Cookie:[session=x4XJfYZsDpSqf_cWigHS3yuT5hqlEntU_WNfJW3j-661sGalr-NcvF6Ey1R340jmvjw8x6O1vie2ctHCW0C0hCjekfDESa3dxIKWt__7FSeidYg1VN-aaTljYeKHfQzuCPvjVak; Path=/; HttpOnly] Strict-Transport-Security:[max-age=31536000; includeSubDomains] X-Content-Type-Options:[nosniff] Content-Type:[application/json; charset=UTF-8] X-Frame-Options:[deny] Date:[Fri, 04 Oct 2019 11:29:01 GMT] Content-Length:[71]] Body:0xc000055100 ContentLength:71 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc0000e6c00 TLS:<nil>}
FAIL command-line-arguments 0.038s
输出
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Invalid authorization, none provided","status":"Bad Request"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Invalid authorization, 1 provided, requires 2","status":"Bad Request"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Invalid authorization, 1 provided, requires 2","status":"Bad Request"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Issue decoding API Key: illegal base64 data at input byte 7","status":"Bad Request"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Invalid JWT timestamp: Expired","status":"Bad Request"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Issue decoding API Key: illegal base64 data at input byte 7","status":"Bad Request"}
2019/10/04 12:01:54 NOTIC: Auth [4537722] via Redis cached value
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Invalid authorization, none provided","status":"Forbidden"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Issue decoding API Key: illegal base64 data at input byte 7","status":"Forbidden"}
2019/10/04 12:01:54 INFO: Handlers.HandleError(): Sent-> {"message":"Error: Session not authenticated","status":"Unauthorized"}
服务器日志
package api
import (
"time"
"os"
"fmt"
"net/http"
"testing"
)
// TODO: Create config loaded from yaml that allows external settings without recompile
// Make sure to update constants for your environment
const (
UseHost = "http://10.11.2.148:8080"
ValidBasic = "cWFfVGVzdDplaih4cVE+JyZzNS9QdThu"
InvalidBasic = "INVALID_BASIC"
ValidBearer = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.X3Jca1o8Db3AdypEu_yYCiOXmy00wgOxHS-3i2cC519UUupBKvYEx1V9x1OysrVWAmJSe7v0fs3iikq6L0Ky6zD6G75B4zmYqAbROFVCuwEKUWgVaykpJI-8u6NKkjGs5qNNxzAiHDQECv7AUUPhOuEeGpxq7y4OSMTDt4ZEYxml_5rNN-g057ViKZiBw9Q0J7FNKqWDf8XK852jcZi8VMM8dHaIv0pBP9M28lP6TaMmEqZRzIJbs2V4YxcMO5KkZhNySNeafycVAZyatiZKYyB0M7_qLSC7A1UEbK1U17n7u2FdE1JCdqKdxONvSFNzInJYwWcY9EU2qsACkRTULQ.pej62Nk9Ra_xVl5P.ZYzrJqx93_GSHgpznT2ZNq9lRWeIPd6r1bEnww0sXczsA84bYMrwLeN_Zb0nl2vvRFem32qUcWfkADVTvYl_3YgQ372darr7TW6geUEG8kQ72LcJ356iHRQ.KFzdokMLDhUlc8xkQ24uYQ"
InvalidBearer = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.ckkQI8TMs7kawGrI6ZA18zVk7NizpwF11aiU015lz2NM6s7gcN0OE0g2td5__TUIIjduHHKt8jCLaeyV0G_j_ai3-GMRLBEiMFizOUZqTUcPpwv0B-DQZ22B-exd-URtZL5RyxxT8FXoLnn7gMEXhURnj06Z0HbSuVIlryzQDwsfFsStw0CpxA1ZCEV3kC54xQetvBiptqJ1IDZaUh0fbAjFDURl9Q5tngyKvG8k6NZE8fpR3hbAukhuAU5cLP8P8DPeHY4wgSXN-xBJIG4vh2EAElHFDcBem_Hf6StkjPltMzUe1qbrLJOpmDNTgHqysCF7xvnJjkuYphGZa_W77g.WZvcU-KICyHg_OFu.LqQc7szbYzP8W3hsSRKWhJsKwFY_Vk38gO2y_-M_HdhgVATYzokKPladyEnOq5fuTegkd69TNwCb8ltC08n_gRLIwqdwgeJDIylWB4Lj_eTW.IJH0URIMFTnrSevMjxgt5Q"
)
type AuthorizationTest int
const (
AuthorizationTestNone AuthorizationTest = 1 + iota // No Authorization in header
AuthorizationTestNoBasic // No Basic in Authorization
AuthorizationTestNoBearer // No Bearer in Authorization
AuthorizationTestInvalidBasic // Invalid Basic in Authorization
AuthorizationTestInvalidBearer // Invalid Bearer in Authorization
AuthorizationTestInvalidBasicBearer // Invalid Basic & Bearer in Authorization
AuthorizationTestValid // valid Basic & Bearer in Authorization
AuthorizationTestBasicNone // Just Basic, none provided
AuthorizationTestBasicInvalid // Just Basic, Invalid Provided
AuthorizationTestBasicValid // Just Basic, Valid Provided
)
type LogType int
const (
LogTypeEndpoint LogType = 1 + iota
LogTypeSubEvent
LogTypeError
LogTypeSuccess
)
var (
Session string
)
func Log(lt LogType, who string, what string) {
if lt == LogTypeEndpoint {
fmt.Printf("\n%s: Testing endpoint /%s...", who, what)
} else if lt == LogTypeSubEvent {
fmt.Printf("\n%s: > %s...", who, what)
} else if lt == LogTypeError {
fmt.Printf("\n%s: ERROR %s\n", who, what)
} else if lt == LogTypeSuccess {
fmt.Printf("\n%s: SUCCESS %s\n", who, what)
} else {
panic("Unknown Log Type")
}
}
func addCookie(w http.ResponseWriter, name string, value string) {
expire := time.Now().AddDate(0, 0, 1)
cookie := http.Cookie{
Name: name,
Value: value,
Expires: expire,
}
http.SetCookie(w, &cookie)
}
func doRequest(test, method string, url string, desiredStatus int, at AuthorizationTest) *http.Response {
req, _ := http.NewRequest(method, url, nil)
req.Header.Add("User-Agent", "GoLang API Test/0.1.0")
req.Header.Add("Cache-Control", "no-cache")
if len(Session) > 0 {
//cookie, _ := req.Cookie("session")
req.Header.Add("Set-Cookie", Session)
}
//req.Header.Add("Accept", "*/*")
//req.Header.Add("Host", UseHost)
//req.Header.Add("Accept-Encoding", "gzip, deflate")
//req.Header.Add("Connection", "keep-alive")
switch at {
// Basic & Bearer
case AuthorizationTestNone:
break
case AuthorizationTestNoBasic:
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", ValidBearer))
case AuthorizationTestNoBearer:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", ValidBasic))
case AuthorizationTestInvalidBasic:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s; Bearer %s", InvalidBasic, ValidBearer))
case AuthorizationTestInvalidBearer:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s; Bearer %s", ValidBasic, InvalidBearer))
case AuthorizationTestInvalidBasicBearer:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s; Bearer %s", InvalidBasic, InvalidBearer))
case AuthorizationTestValid:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s; Bearer %s", ValidBasic, ValidBearer))
// Just Basic
case AuthorizationTestBasicNone:
break
case AuthorizationTestBasicInvalid:
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", InvalidBasic))
case AuthorizationTestBasicValid:
req.Header.Add("Authorization", "Basic YXNoaXNoOmEyNkIpbl5BPyU2V2YhQXNKdw==")
}
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
// Did we just try to authenticate?
//if at == AuthorizationTestValid {
// Was it successful?
//if res.StatusCode == http.StatusOK {
//Kewl, Save the Session for remaining tests
//cookie := res.Header.Get("Set-Cookie")
cookie, err := req.Cookie("session")
if err != nil {
//cookie, err := req.Cookie("session")
Session = cookie.String()
//req.Header.Add("Set-Cookie", cookie.String())
//addCookie(res.Write,"session",cookie)
//session=IOY2A55EKzTrqS1YLjWSq-axdDQAGLqLN5EyHdY5hd4sUTrVIPps3P1EhSP3pyFDFgIyW-EhpqzZeyVGsR_JyueVitAX6MWhpBFQiW2N8KDhedv2LviS_dhM0KGoMtTlRfYlQo-3cySIvA5oPOS_BSEuT2HmjlNCr2DzxDGX1Ig; Path=/; HttpOnly
//Session = cookie
fmt.Println(Session)
}
//}
//}
if res.StatusCode != desiredStatus {
Log(LogTypeError,test,fmt.Sprintf("Expected Status Code %d got %d instead",desiredStatus,res.StatusCode))
fmt.Printf("Exiting on %s request %s ...\n", method, url)
fmt.Printf("\nREQUEST: %+v\n",req)
fmt.Printf("\nRESPONSE: %+v\n\n",res)
os.Exit(1)
}
return res
}
func doRequestAuthorization(caller string, method string, endpoint string) {
url := fmt.Sprintf("%s/%s", UseHost, endpoint)
if endpoint == "authenticate" {
// User Basic & Bearer for Authorization
Log(LogTypeSubEvent,caller,"No Authorization provided in header")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestNone)
Log(LogTypeSubEvent,caller,"Basic missing and bearer present in header")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestNoBasic)
Log(LogTypeSubEvent,caller,"Bearer missing and basic present in header")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestNoBearer)
Log(LogTypeSubEvent,caller,"Invalid Authorization Header (Bad Basic)")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestInvalidBasic)
Log(LogTypeSubEvent,caller,"Invalid Authorization Header (Bad Bearer)")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestInvalidBearer)
Log(LogTypeSubEvent,caller,"Invalid Authorization Header (Bad Basic & Bearer)")
_ = doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestInvalidBasicBearer)
Log(LogTypeSubEvent,caller,"Valid Authorization Header (Good Basic & Bearer)")
_ = doRequest(caller, method, url, http.StatusOK, AuthorizationTestValid)
} else {
// Use Basic only for Authorization
Log(LogTypeSubEvent,caller,"No Basic Authorization provided in header")
_ = doRequest(caller, method, url, http.StatusForbidden, AuthorizationTestBasicNone)
Log(LogTypeSubEvent,caller,"Invalid Basic Authorization Header (Bad Basic)")
_ = doRequest(caller, method, url, http.StatusForbidden, AuthorizationTestBasicInvalid)
Log(LogTypeSubEvent,caller,"Valid Basic Authorization Header (Good Basic)")
_ = doRequest(caller, method, url, http.StatusOK, AuthorizationTestBasicValid)
}
}
// doRequestNoParameters tests endpoints that do not accept any parameters
func doRequestNoParameters(caller string, method string, endpoint string) *http.Response {
Log(LogTypeSubEvent, caller, "No query parameters specified")
url := fmt.Sprintf("%s/%s?foo=bar", UseHost, endpoint)
return doRequest(caller, method, url, http.StatusBadRequest, AuthorizationTestInvalidBasicBearer)
}
func TestAuthenticate(t *testing.T) {
caller := fmt.Sprintf("%s->%s", os.Getenv("REPOSITORY"), t.Name())
Log(LogTypeEndpoint, caller, "authenticate")
doRequestAuthorization(caller, "POST", "authenticate")
Log(LogTypeSuccess, caller, "Ok")
}
// Test "GET", "/bonus"
func TestBonus(t *testing.T) {
endpoint := "bonus"
caller := fmt.Sprintf("%s->%s", os.Getenv("REPOSITORY"), t.Name())
Log(LogTypeEndpoint, caller, endpoint)
doRequestAuthorization(caller, "GET", endpoint)
Log(LogTypeSubEvent,caller,"Valid Query")
url := fmt.Sprintf("%s/%s", UseHost, endpoint)
_ = doRequest(caller, "GET", url, http.StatusOK, AuthorizationTestBasicValid)
}
// TODO: Test "GET", "/category"
func TestCategory(t *testing.T) {
endpoint := "category"
caller := fmt.Sprintf("%s->%s", os.Getenv("REPOSITORY"), t.Name())
Log(LogTypeEndpoint, caller, endpoint)
doRequestAuthorization(caller, "GET", endpoint)
Log(LogTypeSubEvent,caller,"Valid Query")
url := fmt.Sprintf("%s/%s", UseHost, endpoint)
_ = doRequest(caller, "GET", url, http.StatusOK, AuthorizationTestBasicValid)
}
完整来源 提供以显示我正在尝试的全部内容。但是,由于服务器是私有服务器,因此显然无法在您的计算机上工作。
async(flags: .barrier)