mirror of
https://github.com/americanexpress/baton.git
synced 2025-07-06 12:22:29 +00:00
272 lines
7.8 KiB
Go
272 lines
7.8 KiB
Go
/*
|
|
* Copyright 2018 American Express
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* permissions and limitations under the License.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/valyala/fasthttp"
|
|
"io/ioutil"
|
|
"os"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type HTTPTestHandler struct {
|
|
noRequestsReceived uint32
|
|
lastBodyReceived string
|
|
lastMethodReceived string
|
|
lastURIReceived string
|
|
lastHeadersReceived *fasthttp.RequestHeader
|
|
lastTimestamp int64
|
|
}
|
|
|
|
func (h *HTTPTestHandler) HandleRequest(ctx *fasthttp.RequestCtx) {
|
|
atomic.AddUint32(&h.noRequestsReceived, 1)
|
|
atomic.StoreInt64(&h.lastTimestamp, time.Now().Unix())
|
|
h.lastBodyReceived = hex.EncodeToString(ctx.Request.Body())
|
|
h.lastMethodReceived = string(ctx.Request.Header.Method())
|
|
h.lastURIReceived = ctx.Request.URI().String()
|
|
newHeader := fasthttp.RequestHeader{}
|
|
ctx.Request.Header.CopyTo(&newHeader)
|
|
h.lastHeadersReceived = &newHeader
|
|
|
|
}
|
|
|
|
func (h *HTTPTestHandler) reset() {
|
|
h.noRequestsReceived = 0
|
|
h.lastBodyReceived = ""
|
|
h.lastMethodReceived = ""
|
|
h.lastURIReceived = ""
|
|
h.lastTimestamp = 0
|
|
}
|
|
|
|
var serverRunning = false
|
|
var internalHandlerRef *HTTPTestHandler
|
|
var port = "8888"
|
|
|
|
func startServer() *HTTPTestHandler {
|
|
if !serverRunning {
|
|
internalHandlerRef = &HTTPTestHandler{0, "", "", "", &fasthttp.RequestHeader{}, 0}
|
|
serverRunning = true
|
|
go func() {
|
|
err := fasthttp.ListenAndServe(":"+port, internalHandlerRef.HandleRequest)
|
|
if err != nil {
|
|
fmt.Printf("Failed to bind on port %s. Make sure no other service is running on that port and restart the test\n", port)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
return internalHandlerRef
|
|
}
|
|
internalHandlerRef.reset()
|
|
return internalHandlerRef
|
|
}
|
|
|
|
func defaultConfig() Configuration {
|
|
return Configuration{
|
|
"",
|
|
1,
|
|
"",
|
|
0,
|
|
false,
|
|
"GET",
|
|
1,
|
|
"",
|
|
true,
|
|
"http://localhost:" + port,
|
|
0,
|
|
}
|
|
}
|
|
|
|
func setupAndListen(config Configuration) *HTTPTestHandler {
|
|
testHandler := startServer()
|
|
// Give server enough time to spin
|
|
time.Sleep(time.Duration(500) * time.Millisecond)
|
|
// Create a baton instance with given config
|
|
baton := &Baton{configuration: config, result: Result{}}
|
|
baton.run()
|
|
// Give server enough time to receive requests
|
|
time.Sleep(time.Duration(500) * time.Millisecond)
|
|
// Collect results from handler
|
|
return testHandler
|
|
}
|
|
|
|
func TestRequestCount(t *testing.T) {
|
|
noRequestsToSend := 10000
|
|
|
|
config := defaultConfig()
|
|
config.numberOfRequests = noRequestsToSend
|
|
testHandler := setupAndListen(config)
|
|
|
|
reqsReceived := int(testHandler.noRequestsReceived)
|
|
if reqsReceived != noRequestsToSend {
|
|
t.Errorf("Wrong number of requests sent. Expected %d, got %d", noRequestsToSend, reqsReceived)
|
|
}
|
|
}
|
|
|
|
func TestRequestCountWithMoreWorkers(t *testing.T) {
|
|
noRequestsToSend := 100000
|
|
|
|
config := defaultConfig()
|
|
config.concurrency = 10
|
|
config.numberOfRequests = noRequestsToSend
|
|
testHandler := setupAndListen(config)
|
|
|
|
reqsReceived := int(testHandler.noRequestsReceived)
|
|
if reqsReceived != noRequestsToSend {
|
|
t.Errorf("Wrong number of requests sent. Expected %d, got %d", noRequestsToSend, reqsReceived)
|
|
}
|
|
}
|
|
|
|
func TestThatBodyHasCorrectValue(t *testing.T) {
|
|
body := "Hello World"
|
|
bodyBytes := hex.EncodeToString([]byte(body))
|
|
|
|
config := defaultConfig()
|
|
config.body = body
|
|
config.method = "POST"
|
|
testHandler := setupAndListen(config)
|
|
|
|
bytesReceived := testHandler.lastBodyReceived
|
|
if bytesReceived != bodyBytes {
|
|
t.Errorf("The body received by the server didn't match. Expected %s, got %s", bodyBytes, bytesReceived)
|
|
}
|
|
}
|
|
|
|
func TestThatTheCorrectHTTPMethodIsUsed(t *testing.T) {
|
|
method := "DELETE"
|
|
|
|
config := defaultConfig()
|
|
config.method = method
|
|
testHandler := setupAndListen(config)
|
|
|
|
methodReceived := testHandler.lastMethodReceived
|
|
if methodReceived != method {
|
|
t.Errorf("The HTTP method received by the server didn't match. Expected %s, got %s", method, methodReceived)
|
|
}
|
|
}
|
|
|
|
func TestThatServerReceivesCorrectURI(t *testing.T) {
|
|
uri := "http://localhost:" + port + "/path/to/complex?uri&with=html&entities=&#ef"
|
|
|
|
config := defaultConfig()
|
|
config.url = uri
|
|
testHandler := setupAndListen(config)
|
|
|
|
uriReceived := testHandler.lastURIReceived
|
|
if uriReceived != uri {
|
|
t.Errorf("The URI received by the server does not match. Expected %s, got %s.", uri, uriReceived)
|
|
}
|
|
}
|
|
|
|
func TestLoadPostFromTextFile(t *testing.T) {
|
|
body := "Hello World"
|
|
bodyBytes := hex.EncodeToString([]byte(body))
|
|
|
|
config := defaultConfig()
|
|
config.dataFilePath = "test-resources/post-body.txt"
|
|
config.method = "POST"
|
|
testHandler := setupAndListen(config)
|
|
|
|
bytesReceived := testHandler.lastBodyReceived
|
|
if bytesReceived != bodyBytes {
|
|
t.Errorf("The body received by the server didn't match. Expected %s, got %s", bodyBytes, bytesReceived)
|
|
}
|
|
}
|
|
|
|
func TestPostRequestLoadedFromFile(t *testing.T) {
|
|
uri := "http://localhost:" + port
|
|
method := "POST"
|
|
fileContents := method + "," + uri + "," + "Data"
|
|
fileInBytes := []byte(fileContents)
|
|
|
|
fileDir := "test-resources/requests-from-file.txt"
|
|
if ioutil.WriteFile(fileDir, fileInBytes, 0644) != nil {
|
|
t.Errorf("Failed to write a required test case file. Check the directory permissions.")
|
|
}
|
|
defer os.Remove(fileDir)
|
|
|
|
config := defaultConfig()
|
|
config.requestsFromFile = fileDir
|
|
config.numberOfRequests = 2
|
|
testHandler := setupAndListen(config)
|
|
|
|
postBodyInBytes := hex.EncodeToString([]byte("Data"))
|
|
methodReceived := testHandler.lastMethodReceived
|
|
bodyReceived := testHandler.lastBodyReceived
|
|
|
|
if methodReceived != method {
|
|
t.Errorf("The HTTP method received by the server didn't match. Expected %s, got %s", method, methodReceived)
|
|
}
|
|
|
|
if bodyReceived != postBodyInBytes {
|
|
t.Errorf("The body received by the server didn't match. Expected %s, got %s", postBodyInBytes, bodyReceived)
|
|
}
|
|
}
|
|
|
|
func TestThatHeadersAreSetWhenSendingFromFile(t *testing.T) {
|
|
uri := "http://localhost:" + port
|
|
method := "GET"
|
|
fileContents := method + "," + uri + "," + "" + "," + "Content-Type: Hello, Secret: World"
|
|
fileInBytes := []byte(fileContents)
|
|
|
|
fileDir := "test-resources/requests-from-file.txt"
|
|
if ioutil.WriteFile(fileDir, fileInBytes, 0644) != nil {
|
|
t.Errorf("Failed to write a required test case file. Check the directory permissions.")
|
|
}
|
|
defer os.Remove(fileDir)
|
|
|
|
config := defaultConfig()
|
|
config.requestsFromFile = fileDir
|
|
config.numberOfRequests = 1
|
|
testHandler := setupAndListen(config)
|
|
|
|
headerActual := hex.EncodeToString(testHandler.lastHeadersReceived.Peek("Content-Type"))
|
|
headerExpected := hex.EncodeToString([]byte("Hello"))
|
|
if headerExpected != headerActual {
|
|
t.Errorf("Header not found or improperly set, Expected %s, got %s", headerExpected, headerActual)
|
|
}
|
|
|
|
headerActual2 := hex.EncodeToString(testHandler.lastHeadersReceived.Peek("Secret"))
|
|
headerExpected2 := hex.EncodeToString([]byte("World"))
|
|
if headerExpected != headerActual {
|
|
t.Errorf("Header not found or improperly set, Expected %s, got %s", headerExpected2, headerActual2)
|
|
}
|
|
}
|
|
|
|
func TestThatTimeOptionRunsForCorrectAmountOfTime(t *testing.T) {
|
|
duration := 10
|
|
testHandler := startServer()
|
|
timeNow := time.Now().Unix()
|
|
|
|
config := defaultConfig()
|
|
config.duration = duration
|
|
|
|
baton := &Baton{configuration: config, result: Result{}}
|
|
baton.run()
|
|
|
|
time.Sleep(time.Duration(15) * time.Second)
|
|
lastTimeStamp := testHandler.lastTimestamp
|
|
epsilonLow := int64(duration - 1)
|
|
epsilonHigh := int64(duration + 1)
|
|
diff := lastTimeStamp - timeNow
|
|
if diff < epsilonLow || diff > epsilonHigh {
|
|
t.Errorf("Requests sent for longer/shorter than expected. Expected %d, got %d)", duration, diff)
|
|
}
|
|
}
|