OK so I am making a Automated API Test Suite. I want to simulate actual end-user calls and do not want to use httptest.NewRecorder(). Everything is working fine except for the session (not authenticated from server) even though the first test run was testing the authenticate endpoint that only continues with a successful login (basic/Bearer) and session.
How do you track the session from one response to the next request? I really feel like i'm missing something small and stupid - but I am stuck! Included is full source as well as related output and server logs.
Oh, by the way - everything works fine in Postman. But if i export as Go Code and run I get same issue. Got to be something with tracking session.
Currently in the request setup i have:
req.Header.Add("Set-Cookie", Session)
the Session is updated in the response:
cookie := res.Header.Get("Set-Cookie")
if len(cookie) > 0 {
Session = cookie
}
Any help would be much appreciated!
Current Output
=== 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
Server Logs
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"}
Full Source Provided to show what I am attempting in it's entirety. However it will obviously not work from your machine as the server is private.
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)
}
Aucun commentaire:
Enregistrer un commentaire