baton/baton_test.go
2018-02-20 12:55:16 +00:00

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)
}
}