142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/webhooker/internal/config"
|
|
)
|
|
|
|
// envKeySentryDSN is the variable envSentryDSN reads in production.
|
|
const envKeySentryDSN = "SENTRY_DSN"
|
|
|
|
// validSentryDSN is a syntactically complete DSN. The host is under
|
|
// .invalid (RFC 2606), so nothing a test builds around it can reach a
|
|
// real Sentry installation.
|
|
const validSentryDSN = "https://abc123@sentry.invalid/42"
|
|
|
|
// envSentryDSNCase is one row of the envSentryDSN table.
|
|
type envSentryDSNCase struct {
|
|
name string
|
|
set bool
|
|
value string
|
|
expectError bool
|
|
expected string
|
|
}
|
|
|
|
// envSentryDSNCases is the envSentryDSN table. The three invalid
|
|
// values are the ones measured on the defect: each initialised the SDK
|
|
// with an error and left the process serving with reporting off.
|
|
func envSentryDSNCases() []envSentryDSNCase {
|
|
return []envSentryDSNCase{
|
|
{
|
|
name: "unset means reporting off",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "empty means reporting off",
|
|
set: true,
|
|
value: "",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "whitespace means reporting off",
|
|
set: true,
|
|
value: " ",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "a valid DSN is kept",
|
|
set: true,
|
|
value: validSentryDSN,
|
|
expected: validSentryDSN,
|
|
},
|
|
{
|
|
name: "surrounding whitespace is trimmed",
|
|
set: true,
|
|
value: " " + validSentryDSN + "\t",
|
|
expected: validSentryDSN,
|
|
},
|
|
{
|
|
name: "a value that is not a URL is rejected",
|
|
set: true,
|
|
value: "not-a-dsn",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "an unparseable URL is rejected",
|
|
set: true,
|
|
value: "%%%",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "a DSN without a public key is rejected",
|
|
set: true,
|
|
value: "https://example.invalid/1",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "a DSN without a project id is rejected",
|
|
set: true,
|
|
value: "https://abc123@sentry.invalid/",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "a non-HTTP scheme is rejected",
|
|
set: true,
|
|
value: "ftp://abc123@sentry.invalid/42",
|
|
expectError: true,
|
|
},
|
|
}
|
|
}
|
|
|
|
// TestEnvSentryDSN covers the helper directly. What it pins beyond the
|
|
// value is the failure shape: a set-but-unparseable DSN names the
|
|
// variable and the value, exactly as the other fail-loud helpers do,
|
|
// so an operator reads the fix off the message.
|
|
func TestEnvSentryDSN(t *testing.T) {
|
|
for _, tt := range envSentryDSNCases() {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Cannot use t.Parallel() here because t.Setenv
|
|
// is incompatible with parallel subtests.
|
|
if tt.set {
|
|
t.Setenv(envKeySentryDSN, tt.value)
|
|
} else {
|
|
require.NoError(t, os.Unsetenv(envKeySentryDSN))
|
|
}
|
|
|
|
got, err := config.EnvSentryDSNForTest(envKeySentryDSN)
|
|
|
|
if tt.expectError {
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, config.ErrInvalidSentryDSN)
|
|
assert.Contains(t, err.Error(), envKeySentryDSN)
|
|
assert.Contains(t, err.Error(), tt.value)
|
|
assert.Empty(t, got)
|
|
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.expected, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSentryEnabled_TracksTheDSN pins that the one method answering
|
|
// "is anything being reported" agrees with the DSN in every state. The
|
|
// startup log, the SDK initialisation and the sentryhttp middleware
|
|
// all read it, so a log field cannot report reporting as on while
|
|
// nothing is sending.
|
|
func TestSentryEnabled_TracksTheDSN(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assert.False(t, (&config.Config{}).SentryEnabled())
|
|
assert.True(
|
|
t,
|
|
(&config.Config{SentryDSN: validSentryDSN}).SentryEnabled(),
|
|
)
|
|
}
|