From 7c246102ff2fddbfcfa01f133595b24c4d689ba3 Mon Sep 17 00:00:00 2001 From: Aykhan Shahsuvarov Date: Thu, 26 Feb 2026 19:13:42 +0400 Subject: [PATCH] add CI workflow and coverage-gap validation tests --- .github/workflows/e2e.yaml | 24 ++++++++ e2e/coverage_gaps_test.go | 117 +++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 .github/workflows/e2e.yaml create mode 100644 e2e/coverage_gaps_test.go diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml new file mode 100644 index 0000000..c3ef314 --- /dev/null +++ b/.github/workflows/e2e.yaml @@ -0,0 +1,24 @@ +name: e2e-tests + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + e2e: + name: e2e + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-go@v6 + with: + go-version: 1.26.0 + cache: true + - name: run e2e tests + run: go test ./e2e/... -v -count=1 diff --git a/e2e/coverage_gaps_test.go b/e2e/coverage_gaps_test.go new file mode 100644 index 0000000..63434af --- /dev/null +++ b/e2e/coverage_gaps_test.go @@ -0,0 +1,117 @@ +package e2e + +import "testing" + +func TestValidation_InvalidTemplateInMethod(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com", "-r", "1", "-M", "{{ invalid_func }}") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Method[0]") +} + +func TestValidation_InvalidTemplateInParamKey(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com", "-r", "1", "-P", "{{ invalid_func }}=value") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Param[0].Key") +} + +func TestValidation_InvalidTemplateInCookieValue(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com", "-r", "1", "-C", "session={{ invalid_func }}") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Cookie[0].Value[0]") +} + +func TestValidation_InvalidTemplateInURLPath(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com/{{ invalid_func }}", "-r", "1") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "URL.Path") +} + +func TestValidation_InvalidTemplateInValues(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com", "-r", "1", "-V", "A={{ invalid_func }}") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Values[0]") +} + +func TestValidation_ScriptURLWithoutHost(t *testing.T) { + t.Parallel() + + res := run("-U", "http://example.com", "-r", "1", "-lua", "@http://") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "host") +} + +func TestEnvInvalidURL(t *testing.T) { + t.Parallel() + + res := runWithEnv(map[string]string{ + "SARIN_URL": "://bad-url", + "SARIN_REQUESTS": "1", + }, "-q") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "SARIN_URL") +} + +func TestEnvInvalidProxy(t *testing.T) { + t.Parallel() + + res := runWithEnv(map[string]string{ + "SARIN_URL": "http://example.com", + "SARIN_REQUESTS": "1", + "SARIN_PROXY": "://bad-proxy", + }, "-q") + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "SARIN_PROXY") +} + +func TestConfigFileInvalidURLParse(t *testing.T) { + t.Parallel() + + configPath := writeTemp(t, "invalid_url.yaml", ` +url: "://bad-url" +requests: 1 +`) + + res := run("-f", configPath) + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Field 'url'") +} + +func TestConfigFileInvalidProxyParse(t *testing.T) { + t.Parallel() + + configPath := writeTemp(t, "invalid_proxy.yaml", ` +url: "http://example.com" +requests: 1 +proxy: "://bad-proxy" +`) + + res := run("-f", configPath) + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "proxy[0]") +} + +func TestConfigFileInvalidHeadersType(t *testing.T) { + t.Parallel() + + configPath := writeTemp(t, "invalid_headers_type.yaml", ` +url: "http://example.com" +requests: 1 +headers: + - X-Test: value + - 42 +`) + + res := run("-f", configPath) + assertExitCode(t, res, 1) + assertContains(t, res.Stderr, "Failed to parse config file") +}