mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
Merge pull request #1412 from bbx-winner/fix-websocket
feat: support omitting ws url; support multi ws-connections each session
This commit is contained in:
@@ -4,10 +4,12 @@
|
||||
|
||||
**go version**
|
||||
|
||||
- fix: using '@FILEPATH' to indicate the path of the file
|
||||
- fix: using `@FILEPATH` to indicate the path of the file
|
||||
- feat: support indicating type and filename when uploading file
|
||||
- feat: support to infer MIME type of the file automatically
|
||||
|
||||
- feat: support omitting websocket url if not necessary
|
||||
- feat: support multiple websocket connections each session
|
||||
- fix: optimize websocket step initialization
|
||||
|
||||
## v4.1.6 (2022-07-04)
|
||||
|
||||
|
||||
@@ -49,6 +49,22 @@ func TestBuildURL(t *testing.T) {
|
||||
if !assert.Equal(t, url, "https://httpbin.org/get") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// websocket url
|
||||
url = buildURL("wss://ws.postman-echo.com/raw", "")
|
||||
if !assert.Equal(t, url, "wss://ws.postman-echo.com/raw") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
url = buildURL("wss://ws.postman-echo.com", "/raw")
|
||||
if !assert.Equal(t, url, "wss://ws.postman-echo.com/raw") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
url = buildURL("wss://ws.postman-echo.com/raw", "ws://echo.websocket.events")
|
||||
if !assert.Equal(t, url, "ws://echo.websocket.events") {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegexCompileVariable(t *testing.T) {
|
||||
|
||||
@@ -267,6 +267,9 @@ func (r *HRPRunner) newCaseRunner(testcase *TestCase) (*testCaseRunner, error) {
|
||||
return nil, errors.Wrap(err, "parse testcase config failed")
|
||||
}
|
||||
|
||||
// init websocket params
|
||||
initWebSocket(testcase)
|
||||
|
||||
// set testcase timeout in seconds
|
||||
if runner.testCase.Config.Timeout != 0 {
|
||||
timeout := time.Duration(runner.testCase.Config.Timeout*1000) * time.Millisecond
|
||||
|
||||
@@ -17,11 +17,11 @@ type SessionRunner struct {
|
||||
// transactions stores transaction timing info.
|
||||
// key is transaction name, value is map of transaction type and time, e.g. start time and end time.
|
||||
transactions map[string]map[transactionType]time.Time
|
||||
startTime time.Time // record start time of the testcase
|
||||
summary *TestCaseSummary // record test case summary
|
||||
wsConn *websocket.Conn // one websocket connection each session
|
||||
pongResponseChan chan string // channel used to receive pong response message
|
||||
closeResponseChan chan *wsCloseRespObject // channel used to receive close response message
|
||||
startTime time.Time // record start time of the testcase
|
||||
summary *TestCaseSummary // record test case summary
|
||||
wsConnMap map[string]*websocket.Conn // save all websocket connections
|
||||
pongResponseChan chan string // channel used to receive pong response message
|
||||
closeResponseChan chan *wsCloseRespObject // channel used to receive close response message
|
||||
}
|
||||
|
||||
func (r *SessionRunner) resetSession() {
|
||||
@@ -30,6 +30,7 @@ func (r *SessionRunner) resetSession() {
|
||||
r.transactions = make(map[string]map[transactionType]time.Time)
|
||||
r.startTime = time.Now()
|
||||
r.summary = newSummary()
|
||||
r.wsConnMap = make(map[string]*websocket.Conn)
|
||||
r.pongResponseChan = make(chan string, 1)
|
||||
r.closeResponseChan = make(chan *wsCloseRespObject, 1)
|
||||
}
|
||||
@@ -102,11 +103,13 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
||||
|
||||
// close websocket connection after all steps done
|
||||
defer func() {
|
||||
if r.wsConn != nil {
|
||||
log.Info().Str("testcase", config.Name).Msg("websocket disconnected")
|
||||
err := r.wsConn.Close()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("websocket disconnection failed")
|
||||
for _, wsConn := range r.wsConnMap {
|
||||
if wsConn != nil {
|
||||
log.Info().Str("testcase", config.Name).Msg("websocket disconnected")
|
||||
err := wsConn.Close()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("websocket disconnection failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -128,40 +128,45 @@ func (s *StepWebSocket) Run(r *SessionRunner) (*StepResult, error) {
|
||||
return runStepWebSocket(r, s.step)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) OpenConnection(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) withUrl(url ...string) *StepWebSocket {
|
||||
if len(url) == 0 {
|
||||
return s
|
||||
}
|
||||
if len(url) > 1 {
|
||||
log.Warn().Msg("too many WebSocket step URL specified, using first URL")
|
||||
}
|
||||
s.step.WebSocket.URL = url[0]
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) OpenConnection(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsOpen
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) PingPong(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) PingPong(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsPing
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) WriteAndRead(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) WriteAndRead(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsWriteAndRead
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) Read(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) Read(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsRead
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) Write(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) Write(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsWrite
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) CloseConnection(url string) *StepWebSocket {
|
||||
func (s *StepWebSocket) CloseConnection(url ...string) *StepWebSocket {
|
||||
s.step.WebSocket.Type = wsClose
|
||||
s.step.WebSocket.URL = url
|
||||
return s
|
||||
return s.withUrl(url...)
|
||||
}
|
||||
|
||||
func (s *StepWebSocket) WithParams(params map[string]interface{}) *StepWebSocket {
|
||||
@@ -226,6 +231,23 @@ type WebSocketAction struct {
|
||||
Timeout int64 `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
func initWebSocket(testcase *TestCase) {
|
||||
tCase := testcase.ToTCase()
|
||||
for _, step := range tCase.TestSteps {
|
||||
if step.WebSocket == nil {
|
||||
continue
|
||||
}
|
||||
// init websocket action parameters
|
||||
if step.WebSocket.Timeout <= 0 {
|
||||
step.WebSocket.Timeout = defaultTimeout
|
||||
}
|
||||
// close status code range: [1000, 4999]. ref: https://datatracker.ietf.org/doc/html/rfc6455#section-11.7
|
||||
if step.WebSocket.CloseStatusCode < 1000 || step.WebSocket.CloseStatusCode > 4999 {
|
||||
step.WebSocket.CloseStatusCode = defaultCloseStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, err error) {
|
||||
stepResult = &StepResult{
|
||||
Name: step.Name,
|
||||
@@ -259,9 +281,30 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
|
||||
sessionData := newSessionData()
|
||||
parser := r.GetParser()
|
||||
config := r.GetConfig()
|
||||
|
||||
dummyReq := &Request{
|
||||
URL: step.WebSocket.URL,
|
||||
Params: step.WebSocket.Params,
|
||||
Headers: step.WebSocket.Headers,
|
||||
}
|
||||
rb := newRequestBuilder(parser, config, dummyReq)
|
||||
|
||||
err = rb.prepareUrlParams(stepVariables)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = rb.prepareHeaders(stepVariables)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
parsedURL := rb.req.URL.String()
|
||||
parsedHeader := rb.req.Header
|
||||
|
||||
// add request object to step variables, could be used in setup hooks
|
||||
stepVariables["hrp_step_name"] = step.Name
|
||||
stepVariables["hrp_step_request"] = rb.requestMap
|
||||
|
||||
// deal with setup hooks
|
||||
for _, setupHook := range step.SetupHooks {
|
||||
@@ -271,8 +314,6 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
}
|
||||
}
|
||||
|
||||
// init websocket frame parameters
|
||||
initStepWebsocket(step.WebSocket)
|
||||
var resp interface{}
|
||||
start := time.Now()
|
||||
|
||||
@@ -282,21 +323,18 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
}
|
||||
switch step.WebSocket.Type {
|
||||
case wsOpen:
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Msg("open websocket connection")
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Str("url", parsedURL).Msg("open websocket connection")
|
||||
// use the current websocket connection if existed
|
||||
if r.wsConn != nil {
|
||||
if r.wsConnMap[parsedURL] != nil {
|
||||
break
|
||||
}
|
||||
resp, err = openWithTimeout(sessionData, r, step, stepVariables)
|
||||
resp, err = openWithTimeout(parsedURL, parsedHeader, r, step)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "open connection failed")
|
||||
}
|
||||
case wsPing:
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Msg("send ping and expect pong")
|
||||
if r.wsConn == nil {
|
||||
return stepResult, errors.Errorf("try to use existing connection, but there is no connection")
|
||||
}
|
||||
err = writeWebSocket(r, step, stepVariables)
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Str("url", parsedURL).Msg("send ping and expect pong")
|
||||
err = writeWebSocket(parsedURL, r, step, stepVariables)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "send ping message failed")
|
||||
}
|
||||
@@ -313,30 +351,30 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
}
|
||||
}()
|
||||
case wsWriteAndRead:
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Msg("write a message and read response")
|
||||
err = writeWebSocket(r, step, stepVariables)
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Str("url", parsedURL).Msg("write a message and read response")
|
||||
err = writeWebSocket(parsedURL, r, step, stepVariables)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "write message failed")
|
||||
}
|
||||
resp, err = readMessageWithTimeout(r, step)
|
||||
resp, err = readMessageWithTimeout(parsedURL, r, step)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "read message failed")
|
||||
}
|
||||
case wsRead:
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Msg("read only")
|
||||
resp, err = readMessageWithTimeout(r, step)
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Str("url", parsedURL).Msg("read only")
|
||||
resp, err = readMessageWithTimeout(parsedURL, r, step)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "read message failed")
|
||||
}
|
||||
case wsWrite:
|
||||
log.Info().Msg("write only")
|
||||
err = writeWebSocket(r, step, stepVariables)
|
||||
log.Info().Str("url", parsedURL).Msg("write only")
|
||||
err = writeWebSocket(parsedURL, r, step, stepVariables)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "write message failed")
|
||||
}
|
||||
case wsClose:
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Msg("close webSocket connection")
|
||||
resp, err = closeWithTimeout(r, step, stepVariables)
|
||||
log.Info().Int64("timeout(ms)", step.WebSocket.Timeout).Str("url", parsedURL).Msg("close webSocket connection")
|
||||
resp, err = closeWithTimeout(parsedURL, r, step, stepVariables)
|
||||
if err != nil {
|
||||
return stepResult, errors.Wrap(err, "close connection failed")
|
||||
}
|
||||
@@ -371,6 +409,7 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
}
|
||||
|
||||
if respObj != nil {
|
||||
sessionData.ReqResps.Request = rb.requestMap
|
||||
sessionData.ReqResps.Response = builtin.FormatResponse(respObj.respObjMeta)
|
||||
|
||||
// extract variables from response
|
||||
@@ -428,56 +467,11 @@ func printWebSocketResponse(resp interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initStepWebsocket(stepWebSocket *WebSocketAction) {
|
||||
if stepWebSocket == nil {
|
||||
return
|
||||
}
|
||||
if stepWebSocket.Timeout <= 0 {
|
||||
stepWebSocket.Timeout = defaultTimeout
|
||||
}
|
||||
// close status code range: [1000, 4999]. ref: https://datatracker.ietf.org/doc/html/rfc6455#section-11.7
|
||||
if stepWebSocket.CloseStatusCode < 1000 || stepWebSocket.CloseStatusCode > 4999 {
|
||||
stepWebSocket.CloseStatusCode = defaultCloseStatus
|
||||
}
|
||||
}
|
||||
|
||||
// prepareDialInfo prepares url and headers before opening connection
|
||||
func prepareDialInfo(r *SessionRunner, step *TStep, stepVariables map[string]interface{}) (*requestBuilder, error) {
|
||||
parser := r.GetParser()
|
||||
config := r.GetConfig()
|
||||
|
||||
dummyReq := &Request{
|
||||
URL: step.WebSocket.URL,
|
||||
Params: step.WebSocket.Params,
|
||||
Headers: step.WebSocket.Headers,
|
||||
}
|
||||
dummyBuilder := newRequestBuilder(parser, config, dummyReq)
|
||||
|
||||
err := dummyBuilder.prepareUrlParams(stepVariables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dummyBuilder.prepareHeaders(stepVariables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dummyBuilder, nil
|
||||
}
|
||||
|
||||
func openWithTimeout(d *SessionData, r *SessionRunner, step *TStep, stepVariables map[string]interface{}) (*http.Response, error) {
|
||||
func openWithTimeout(urlStr string, requestHeader http.Header, r *SessionRunner, step *TStep) (*http.Response, error) {
|
||||
openResponseChan := make(chan *http.Response)
|
||||
errorChan := make(chan error)
|
||||
go func() {
|
||||
// prepare request and dial
|
||||
rb, err := prepareDialInfo(r, step, stepVariables)
|
||||
if err != nil {
|
||||
errorChan <- errors.Wrap(err, "prepare dail info failed")
|
||||
return
|
||||
}
|
||||
d.ReqResps.Request = rb.requestMap
|
||||
conn, resp, err := r.hrpRunner.wsDialer.Dial(rb.req.URL.String(), rb.req.Header)
|
||||
conn, resp, err := r.hrpRunner.wsDialer.Dial(urlStr, requestHeader)
|
||||
if err != nil {
|
||||
errorChan <- errors.Wrap(err, "dial tcp failed")
|
||||
return
|
||||
@@ -499,7 +493,7 @@ func openWithTimeout(d *SessionData, r *SessionRunner, step *TStep, stepVariable
|
||||
}
|
||||
return nil
|
||||
})
|
||||
r.wsConn = conn
|
||||
r.wsConnMap[urlStr] = conn
|
||||
openResponseChan <- resp
|
||||
}()
|
||||
|
||||
@@ -515,14 +509,15 @@ func openWithTimeout(d *SessionData, r *SessionRunner, step *TStep, stepVariable
|
||||
}
|
||||
}
|
||||
|
||||
func readMessageWithTimeout(r *SessionRunner, step *TStep) (*wsReadRespObject, error) {
|
||||
if r.wsConn == nil {
|
||||
func readMessageWithTimeout(urlString string, r *SessionRunner, step *TStep) (*wsReadRespObject, error) {
|
||||
wsConn := r.wsConnMap[urlString]
|
||||
if wsConn == nil {
|
||||
return nil, errors.New("try to use existing connection, but there is no connection")
|
||||
}
|
||||
readResponseChan := make(chan *wsReadRespObject)
|
||||
errorChan := make(chan error)
|
||||
go func() {
|
||||
messageType, message, err := r.wsConn.ReadMessage()
|
||||
messageType, message, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
} else {
|
||||
@@ -544,18 +539,18 @@ func readMessageWithTimeout(r *SessionRunner, step *TStep) (*wsReadRespObject, e
|
||||
}
|
||||
}
|
||||
|
||||
func writeWebSocket(r *SessionRunner, step *TStep, stepVariables map[string]interface{}) error {
|
||||
if r.wsConn == nil {
|
||||
func writeWebSocket(urlString string, r *SessionRunner, step *TStep, stepVariables map[string]interface{}) error {
|
||||
wsConn := r.wsConnMap[urlString]
|
||||
if wsConn == nil {
|
||||
return errors.New("try to use existing connection, but there is no connection")
|
||||
}
|
||||
// TODO: only support writing one kind of message each step here?
|
||||
// check priority: text message > binary message
|
||||
if step.WebSocket.TextMessage != nil {
|
||||
parsedMessage, parseErr := r.parser.Parse(step.WebSocket.TextMessage, stepVariables)
|
||||
if parseErr != nil {
|
||||
return parseErr
|
||||
}
|
||||
writeErr := writeWithType(r.wsConn, step, websocket.TextMessage, parsedMessage)
|
||||
writeErr := writeWithType(wsConn, step, websocket.TextMessage, parsedMessage)
|
||||
if writeErr != nil {
|
||||
return writeErr
|
||||
}
|
||||
@@ -564,13 +559,13 @@ func writeWebSocket(r *SessionRunner, step *TStep, stepVariables map[string]inte
|
||||
if parseErr != nil {
|
||||
return parseErr
|
||||
}
|
||||
writeErr := writeWithType(r.wsConn, step, websocket.BinaryMessage, parsedMessage)
|
||||
writeErr := writeWithType(wsConn, step, websocket.BinaryMessage, parsedMessage)
|
||||
if writeErr != nil {
|
||||
return writeErr
|
||||
}
|
||||
} else {
|
||||
log.Info().Msg("step with empty message")
|
||||
err := writeWithAction(r.wsConn, step, websocket.BinaryMessage, []byte{})
|
||||
err := writeWithAction(wsConn, step, websocket.BinaryMessage, []byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -610,13 +605,14 @@ func writeWithAction(c *websocket.Conn, step *TStep, messageType int, message []
|
||||
}
|
||||
}
|
||||
|
||||
func closeWithTimeout(r *SessionRunner, step *TStep, stepVariables map[string]interface{}) (*wsCloseRespObject, error) {
|
||||
if r.wsConn == nil {
|
||||
func closeWithTimeout(urlString string, r *SessionRunner, step *TStep, stepVariables map[string]interface{}) (*wsCloseRespObject, error) {
|
||||
wsConn := r.wsConnMap[urlString]
|
||||
if wsConn == nil {
|
||||
return nil, errors.New("no connection needs to be closed")
|
||||
}
|
||||
errorChan := make(chan error)
|
||||
go func() {
|
||||
err := writeWebSocket(r, step, stepVariables)
|
||||
err := writeWebSocket(urlString, r, step, stepVariables)
|
||||
if err != nil {
|
||||
errorChan <- errors.Wrap(err, "send close message failed")
|
||||
return
|
||||
@@ -626,7 +622,7 @@ func closeWithTimeout(r *SessionRunner, step *TStep, stepVariables map[string]in
|
||||
var message []byte
|
||||
var readErr error
|
||||
for readErr == nil {
|
||||
mt, message, readErr = r.wsConn.ReadMessage()
|
||||
mt, message, readErr = wsConn.ReadMessage()
|
||||
if readErr == nil {
|
||||
log.Info().
|
||||
Str("type", MessageType(mt).toString()).
|
||||
|
||||
@@ -56,38 +56,39 @@ func TestHTTPProtocol(t *testing.T) {
|
||||
func TestWebSocketProtocol(t *testing.T) {
|
||||
testcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("run request with WebSocket protocol").
|
||||
SetBaseURL("ws://echo.websocket.events").
|
||||
WithVariables(map[string]interface{}{
|
||||
"n": 5,
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
"file": "./demo_file_load_ws_message.txt",
|
||||
"n": 5,
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
"file": "./demo_file_load_ws_message.txt",
|
||||
"wsEchoURL": "ws://echo.websocket.events",
|
||||
"wsPostmanURL": "wss://ws.postman-echo.com/raw",
|
||||
}),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("open connection").
|
||||
WebSocket().
|
||||
OpenConnection("/").
|
||||
OpenConnection("$wsEchoURL"). // absolute url specified, disable base url anyway
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
|
||||
Validate().
|
||||
AssertEqual("status_code", 101, "check open status code").
|
||||
AssertEqual("headers.Connection", "Upgrade", "check headers"),
|
||||
hrp.NewStep("ping pong test").
|
||||
WebSocket().
|
||||
PingPong("/").
|
||||
PingPong("$wsEchoURL").
|
||||
WithTimeout(5000),
|
||||
hrp.NewStep("read sponsor info").
|
||||
WebSocket().
|
||||
Read("/").
|
||||
Read("$wsEchoURL").
|
||||
WithTimeout(5000).
|
||||
Validate().
|
||||
AssertContains("body", "Lob.com", "check sponsor message"),
|
||||
hrp.NewStep("write json").
|
||||
WebSocket().
|
||||
Write("/").
|
||||
Write("$wsEchoURL").
|
||||
WithTextMessage(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}"}),
|
||||
hrp.NewStep("read json").
|
||||
WebSocket().
|
||||
Read("/").
|
||||
Read("$wsEchoURL").
|
||||
Extract().
|
||||
WithJmesPath("body.foo1", "varFoo1").
|
||||
Validate().
|
||||
@@ -95,25 +96,163 @@ func TestWebSocketProtocol(t *testing.T) {
|
||||
AssertEqual("body.foo2", 12.3, "check json foo2"),
|
||||
hrp.NewStep("write and read text").
|
||||
WebSocket().
|
||||
WriteAndRead("/").
|
||||
WriteAndRead("$wsEchoURL").
|
||||
WithTextMessage("$varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body", 5, "check length equal"),
|
||||
hrp.NewStep("write and read binary file").
|
||||
WebSocket().
|
||||
WriteAndRead("/").
|
||||
WriteAndRead("$wsEchoURL").
|
||||
WithBinaryMessage("${load_ws_message($file)}"),
|
||||
hrp.NewStep("write something redundant").
|
||||
WebSocket().
|
||||
Write("/").
|
||||
Write("$wsEchoURL").
|
||||
WithTextMessage("have a nice day!"),
|
||||
hrp.NewStep("write something redundant").
|
||||
WebSocket().
|
||||
Write("/").
|
||||
Write("$wsEchoURL").
|
||||
WithTextMessage("balabala ..."),
|
||||
hrp.NewStep("close connection").
|
||||
WebSocket().
|
||||
CloseConnection("/").
|
||||
CloseConnection("$wsEchoURL").
|
||||
WithTimeout(30000).
|
||||
WithCloseStatus(1000).
|
||||
Validate().
|
||||
AssertEqual("status_code", 1000, "check close status code"),
|
||||
hrp.NewStep("[postman-echo] open connection").
|
||||
WebSocket().
|
||||
OpenConnection("$wsPostmanURL").
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
|
||||
Validate().
|
||||
AssertEqual("status_code", 101, "check open status code").
|
||||
AssertEqualFold("headers.Connection", "Upgrade", "check headers").
|
||||
AssertEqualFold("headers.Server", "nginx", "check server").
|
||||
AssertEqualFold("headers.Upgrade", "websocket", "checkout upgrade"),
|
||||
hrp.NewStep("[postman-echo] write json").
|
||||
WebSocket().
|
||||
Write("$wsPostmanURL").
|
||||
WithTextMessage(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}"}),
|
||||
hrp.NewStep("[postman-echo] read json").
|
||||
WebSocket().
|
||||
Read("$wsPostmanURL").
|
||||
Validate().
|
||||
AssertLengthEqual("body.foo1", 5, "check json foo1").
|
||||
AssertEqual("body.foo2", 12.3, "check json foo2"),
|
||||
hrp.NewStep("[postman-echo] write and read text").
|
||||
WebSocket().
|
||||
WriteAndRead("$wsPostmanURL").
|
||||
WithTextMessage("$varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body", 5, "check length equal"),
|
||||
hrp.NewStep("[postman-echo] close connection").
|
||||
WebSocket().
|
||||
CloseConnection("$wsPostmanURL").
|
||||
WithTimeout(30000).
|
||||
WithCloseStatus(1000).
|
||||
Validate().
|
||||
AssertEqual("status_code", 1000, "check close status code"),
|
||||
},
|
||||
}
|
||||
err := hrp.NewRunner(t).Run(testcase)
|
||||
if err != nil {
|
||||
t.Fatalf("run testcase error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketProtocolUsingRelativeURL(t *testing.T) {
|
||||
testcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("run request with WebSocket protocol").
|
||||
SetBaseURL("wss://ws.postman-echo.com").
|
||||
WithVariables(map[string]interface{}{
|
||||
"n": 5,
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
"file": "./demo_file_load_ws_message.txt",
|
||||
}),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("open connection").
|
||||
WebSocket().
|
||||
OpenConnection("/raw"). // relative url specified ==> wss://ws.postman-echo.com/raw
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
|
||||
Validate().
|
||||
AssertEqual("status_code", 101, "check open status code").
|
||||
AssertEqualFold("headers.Connection", "Upgrade", "check headers").
|
||||
AssertEqualFold("headers.Server", "nginx", "check server").
|
||||
AssertEqualFold("headers.Upgrade", "websocket", "checkout upgrade"),
|
||||
hrp.NewStep("write json").
|
||||
WebSocket().
|
||||
Write("/raw").
|
||||
WithTextMessage(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}"}),
|
||||
hrp.NewStep("read json").
|
||||
WebSocket().
|
||||
Read("/raw").
|
||||
Extract().
|
||||
WithJmesPath("body.foo1", "varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body.foo1", 5, "check json foo1").
|
||||
AssertEqual("body.foo2", 12.3, "check json foo2"),
|
||||
hrp.NewStep("write and read text").
|
||||
WebSocket().
|
||||
WriteAndRead("/raw").
|
||||
WithTextMessage("$varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body", 5, "check length equal"),
|
||||
hrp.NewStep("close connection").
|
||||
WebSocket().
|
||||
CloseConnection("/raw").
|
||||
WithTimeout(30000).
|
||||
WithCloseStatus(1000).
|
||||
Validate().
|
||||
AssertEqual("status_code", 1000, "check close status code"),
|
||||
},
|
||||
}
|
||||
err := hrp.NewRunner(t).Run(testcase)
|
||||
if err != nil {
|
||||
t.Fatalf("run testcase error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketProtocolUsingBaseURL(t *testing.T) {
|
||||
testcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("run request with WebSocket protocol").
|
||||
SetBaseURL("wss://ws.postman-echo.com/raw").
|
||||
WithVariables(map[string]interface{}{
|
||||
"n": 5,
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
"file": "./demo_file_load_ws_message.txt",
|
||||
}),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("open connection").
|
||||
WebSocket().
|
||||
OpenConnection(). // no url specified, using base url instead
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
|
||||
Validate().
|
||||
AssertEqual("status_code", 101, "check open status code").
|
||||
AssertEqualFold("headers.Connection", "Upgrade", "check headers").
|
||||
AssertEqualFold("headers.Server", "nginx", "check server").
|
||||
AssertEqualFold("headers.Upgrade", "websocket", "checkout upgrade"),
|
||||
hrp.NewStep("write json").
|
||||
WebSocket().
|
||||
Write().
|
||||
WithTextMessage(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}"}),
|
||||
hrp.NewStep("read json").
|
||||
WebSocket().
|
||||
Read().
|
||||
Extract().
|
||||
WithJmesPath("body.foo1", "varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body.foo1", 5, "check json foo1").
|
||||
AssertEqual("body.foo2", 12.3, "check json foo2"),
|
||||
hrp.NewStep("write and read text").
|
||||
WebSocket().
|
||||
WriteAndRead().
|
||||
WithTextMessage("$varFoo1").
|
||||
Validate().
|
||||
AssertLengthEqual("body", 5, "check length equal"),
|
||||
hrp.NewStep("close connection").
|
||||
WebSocket().
|
||||
CloseConnection().
|
||||
WithTimeout(30000).
|
||||
WithCloseStatus(1000).
|
||||
Validate().
|
||||
|
||||
Reference in New Issue
Block a user