mirror of
https://github.com/aykhans/sarin.git
synced 2026-02-28 06:49:13 +00:00
283 lines
6.3 KiB
Go
283 lines
6.3 KiB
Go
package e2e
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
// --- Multiple config files ---
|
|
|
|
func TestMultipleConfigFiles(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config1 := `
|
|
url: "` + cs.URL + `"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
headers:
|
|
- X-From-File1: yes
|
|
`
|
|
config2 := `
|
|
headers:
|
|
- X-From-File2: yes
|
|
`
|
|
path1 := writeTemp(t, "merge1.yaml", config1)
|
|
path2 := writeTemp(t, "merge2.yaml", config2)
|
|
|
|
res := run("-f", path1, "-f", path2)
|
|
assertExitCode(t, res, 0)
|
|
|
|
req := cs.lastRequest()
|
|
if v := req.Headers["X-From-File1"]; len(v) == 0 || v[0] != "yes" {
|
|
t.Errorf("expected X-From-File1: yes, got %v", v)
|
|
}
|
|
if v := req.Headers["X-From-File2"]; len(v) == 0 || v[0] != "yes" {
|
|
t.Errorf("expected X-From-File2: yes, got %v", v)
|
|
}
|
|
}
|
|
|
|
func TestMultipleConfigFilesScalarOverride(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
// Second config file overrides URL from first
|
|
config1 := `
|
|
url: "http://should-be-overridden.invalid"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
`
|
|
config2 := `
|
|
url: "` + cs.URL + `"
|
|
`
|
|
path1 := writeTemp(t, "merge_scalar1.yaml", config1)
|
|
path2 := writeTemp(t, "merge_scalar2.yaml", config2)
|
|
|
|
res := run("-f", path1, "-f", path2)
|
|
assertExitCode(t, res, 0)
|
|
|
|
if cs.requestCount() != 1 {
|
|
t.Errorf("expected request to go to second config's URL, got %d requests", cs.requestCount())
|
|
}
|
|
}
|
|
|
|
// --- Three-way merge: env + config file + CLI ---
|
|
|
|
func TestThreeWayMergePriority(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
method: PUT
|
|
headers:
|
|
- X-From-Config: config-value
|
|
`
|
|
configPath := writeTemp(t, "three_way.yaml", config)
|
|
|
|
// ENV sets URL and header, config file sets method and header, CLI overrides URL
|
|
res := runWithEnv(map[string]string{
|
|
"SARIN_HEADER": "X-From-Env: env-value",
|
|
}, "-U", cs.URL, "-r", "1", "-q", "-o", "json", "-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
req := cs.lastRequest()
|
|
// Method should be PUT from config (not default GET)
|
|
if req.Method != http.MethodPut {
|
|
t.Errorf("expected method PUT from config, got %s", req.Method)
|
|
}
|
|
// Header from config file should be present
|
|
if v := req.Headers["X-From-Config"]; len(v) == 0 || v[0] != "config-value" {
|
|
t.Errorf("expected X-From-Config from config file, got %v", v)
|
|
}
|
|
// Header from env should be present
|
|
if v := req.Headers["X-From-Env"]; len(v) == 0 || v[0] != "env-value" {
|
|
t.Errorf("expected X-From-Env from env, got %v", v)
|
|
}
|
|
}
|
|
|
|
// --- Config file nesting depth ---
|
|
|
|
func TestConfigFileNestedMaxDepth(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
// Create a chain of 12 config files (exceeds max depth of 10)
|
|
// The innermost file has the actual URL config
|
|
// When depth is exceeded, inner files are silently ignored
|
|
|
|
files := make([]string, 12)
|
|
|
|
// Innermost file (index 11) - has the real config
|
|
files[11] = writeTemp(t, "depth11.yaml", `
|
|
url: "`+cs.URL+`"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
headers:
|
|
- X-Depth: deep
|
|
`)
|
|
|
|
// Chain each file to include the next one
|
|
for i := 10; i >= 0; i-- {
|
|
content := `configFile: "` + files[i+1] + `"`
|
|
files[i] = writeTemp(t, "depth"+string(rune('0'+i))+".yaml", content)
|
|
}
|
|
|
|
// The outermost file: this will recurse but max depth will prevent
|
|
// reaching the innermost file with the URL
|
|
res := run("-f", files[0], "-q")
|
|
// This should fail because URL is never reached (too deep)
|
|
assertExitCode(t, res, 1)
|
|
}
|
|
|
|
// --- YAML format flexibility ---
|
|
|
|
func TestConfigFileParamsMapFormat(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
url: "` + cs.URL + `"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
params:
|
|
key1: value1
|
|
key2: value2
|
|
`
|
|
configPath := writeTemp(t, "params_map.yaml", config)
|
|
|
|
res := run("-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
req := cs.lastRequest()
|
|
if v := req.Query["key1"]; len(v) == 0 || v[0] != "value1" {
|
|
t.Errorf("expected key1=value1, got %v", v)
|
|
}
|
|
if v := req.Query["key2"]; len(v) == 0 || v[0] != "value2" {
|
|
t.Errorf("expected key2=value2, got %v", v)
|
|
}
|
|
}
|
|
|
|
func TestConfigFileHeadersMapFormat(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
url: "` + cs.URL + `"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
headers:
|
|
X-Map-A: map-val-a
|
|
X-Map-B: map-val-b
|
|
`
|
|
configPath := writeTemp(t, "headers_map.yaml", config)
|
|
|
|
res := run("-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
req := cs.lastRequest()
|
|
if v := req.Headers["X-Map-A"]; len(v) == 0 || v[0] != "map-val-a" {
|
|
t.Errorf("expected X-Map-A: map-val-a, got %v", v)
|
|
}
|
|
if v := req.Headers["X-Map-B"]; len(v) == 0 || v[0] != "map-val-b" {
|
|
t.Errorf("expected X-Map-B: map-val-b, got %v", v)
|
|
}
|
|
}
|
|
|
|
func TestConfigFileCookiesMapFormat(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
url: "` + cs.URL + `"
|
|
requests: 1
|
|
quiet: true
|
|
output: json
|
|
cookies:
|
|
sess: abc
|
|
token: xyz
|
|
`
|
|
configPath := writeTemp(t, "cookies_map.yaml", config)
|
|
|
|
res := run("-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
req := cs.lastRequest()
|
|
if v, ok := req.Cookies["sess"]; !ok || v != "abc" {
|
|
t.Errorf("expected cookie sess=abc, got %v", req.Cookies)
|
|
}
|
|
if v, ok := req.Cookies["token"]; !ok || v != "xyz" {
|
|
t.Errorf("expected cookie token=xyz, got %v", req.Cookies)
|
|
}
|
|
}
|
|
|
|
func TestConfigFileMultipleBodies(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
url: "` + cs.URL + `"
|
|
requests: 10
|
|
concurrency: 1
|
|
method: POST
|
|
quiet: true
|
|
output: json
|
|
body:
|
|
- "body-one"
|
|
- "body-two"
|
|
`
|
|
configPath := writeTemp(t, "multi_body.yaml", config)
|
|
|
|
res := run("-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
bodies := map[string]bool{}
|
|
for _, req := range cs.allRequests() {
|
|
bodies[req.Body] = true
|
|
}
|
|
if !bodies["body-one"] || !bodies["body-two"] {
|
|
t.Errorf("expected both body-one and body-two to appear, got %v", bodies)
|
|
}
|
|
}
|
|
|
|
func TestConfigFileMultipleMethods(t *testing.T) {
|
|
t.Parallel()
|
|
cs := newCaptureServer()
|
|
defer cs.Close()
|
|
|
|
config := `
|
|
url: "` + cs.URL + `"
|
|
requests: 10
|
|
concurrency: 1
|
|
quiet: true
|
|
output: json
|
|
method:
|
|
- GET
|
|
- POST
|
|
`
|
|
configPath := writeTemp(t, "multi_method.yaml", config)
|
|
|
|
res := run("-f", configPath)
|
|
assertExitCode(t, res, 0)
|
|
|
|
methods := map[string]bool{}
|
|
for _, req := range cs.allRequests() {
|
|
methods[req.Method] = true
|
|
}
|
|
if !methods["GET"] || !methods["POST"] {
|
|
t.Errorf("expected both GET and POST, got %v", methods)
|
|
}
|
|
}
|