Add e2e tests

This commit is contained in:
2026-02-18 00:03:59 +04:00
parent d197e90103
commit 4b3230bb27
26 changed files with 4490 additions and 3 deletions

282
e2e/config_merge_test.go Normal file
View File

@@ -0,0 +1,282 @@
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)
}
}