mirror of https://github.com/docker/docs.git
363 lines
9.6 KiB
Go
363 lines
9.6 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/bugsnag/bugsnag-go"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const envPrefix = "NOTARY_TESTING_ENV_PREFIX"
|
|
|
|
// initializes a viper object with test configuration
|
|
func configure(jsonConfig string) *viper.Viper {
|
|
config := viper.New()
|
|
SetupViper(config, envPrefix)
|
|
config.SetConfigType("json")
|
|
config.ReadConfig(bytes.NewBuffer([]byte(jsonConfig)))
|
|
return config
|
|
}
|
|
|
|
// Sets the environment variables in the given map, prefixed by envPrefix.
|
|
func setupEnvironmentVariables(t *testing.T, vars map[string]string) {
|
|
for k, v := range vars {
|
|
err := os.Setenv(fmt.Sprintf("%s_%s", envPrefix, k), v)
|
|
assert.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
// Unsets whatever environment variables were set with this map
|
|
func cleanupEnvironmentVariables(t *testing.T, vars map[string]string) {
|
|
for k := range vars {
|
|
err := os.Unsetenv(fmt.Sprintf("%s_%s", envPrefix, k))
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
}
|
|
|
|
// An error is returned if the log level is not parsable
|
|
func TestParseInvalidLogLevel(t *testing.T) {
|
|
_, err := ParseLogLevel(configure(`{"logging": {"level": "horatio"}}`),
|
|
logrus.DebugLevel)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not a valid logrus Level")
|
|
}
|
|
|
|
// If there is no logging level configured it is set to the default level
|
|
func TestParseNoLogLevel(t *testing.T) {
|
|
empties := []string{`{}`, `{"logging": {}}`}
|
|
for _, configJSON := range empties {
|
|
lvl, err := ParseLogLevel(configure(configJSON), logrus.DebugLevel)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, logrus.DebugLevel, lvl)
|
|
}
|
|
}
|
|
|
|
// If there is logging level configured, it is set to the configured one
|
|
func TestParseLogLevel(t *testing.T) {
|
|
lvl, err := ParseLogLevel(configure(`{"logging": {"level": "error"}}`),
|
|
logrus.DebugLevel)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, logrus.ErrorLevel, lvl)
|
|
}
|
|
|
|
func TestParseLogLevelWithEnvironmentVariables(t *testing.T) {
|
|
vars := map[string]string{"LOGGING_LEVEL": "error"}
|
|
setupEnvironmentVariables(t, vars)
|
|
defer cleanupEnvironmentVariables(t, vars)
|
|
|
|
lvl, err := ParseLogLevel(configure(`{}`),
|
|
logrus.DebugLevel)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, logrus.ErrorLevel, lvl)
|
|
}
|
|
|
|
// An error is returned if there's no API key
|
|
func TestParseInvalidBugsnag(t *testing.T) {
|
|
_, err := ParseBugsnag(configure(
|
|
`{"reporting": {"bugsnag": {"endpoint": "http://12345"}}}`))
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "must provide an API key")
|
|
}
|
|
|
|
// If there's no bugsnag, a nil pointer is returned
|
|
func TestParseNoBugsnag(t *testing.T) {
|
|
empties := []string{`{}`, `{"reporting": {}}`}
|
|
for _, configJSON := range empties {
|
|
bugconf, err := ParseBugsnag(configure(configJSON))
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, bugconf)
|
|
}
|
|
}
|
|
|
|
func TestParseBugsnag(t *testing.T) {
|
|
config := configure(`{
|
|
"reporting": {
|
|
"bugsnag": {
|
|
"api_key": "12345",
|
|
"release_stage": "production",
|
|
"endpoint": "http://1234.com"
|
|
}
|
|
}
|
|
}`)
|
|
|
|
expected := bugsnag.Configuration{
|
|
APIKey: "12345",
|
|
ReleaseStage: "production",
|
|
Endpoint: "http://1234.com",
|
|
}
|
|
|
|
bugconf, err := ParseBugsnag(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *bugconf)
|
|
}
|
|
|
|
func TestParseBugsnagWithEnvironmentVariables(t *testing.T) {
|
|
config := configure(`{
|
|
"reporting": {
|
|
"bugsnag": {
|
|
"api_key": "12345",
|
|
"release_stage": "staging"
|
|
}
|
|
}
|
|
}`)
|
|
|
|
vars := map[string]string{
|
|
"REPORTING_BUGSNAG_RELEASE_STAGE": "production",
|
|
"REPORTING_BUGSNAG_ENDPOINT": "http://1234.com",
|
|
}
|
|
setupEnvironmentVariables(t, vars)
|
|
defer cleanupEnvironmentVariables(t, vars)
|
|
|
|
expected := bugsnag.Configuration{
|
|
APIKey: "12345",
|
|
ReleaseStage: "production",
|
|
Endpoint: "http://1234.com",
|
|
}
|
|
|
|
bugconf, err := ParseBugsnag(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *bugconf)
|
|
}
|
|
|
|
// If the storage backend is invalid or not provided, an error is returned.
|
|
func TestParseInvalidStorageBackend(t *testing.T) {
|
|
invalids := []string{
|
|
`{"storage": {"backend": "postgres", "db_url": "1234"}}`,
|
|
`{"storage": {"db_url": "12345"}}`,
|
|
`{"storage": {}}`,
|
|
`{}`,
|
|
}
|
|
for _, configJSON := range invalids {
|
|
_, err := ParseStorage(configure(configJSON),
|
|
[]string{MySQLBackend, SqliteBackend})
|
|
assert.Error(t, err, fmt.Sprintf("'%s' should be an error", configJSON))
|
|
assert.Contains(t, err.Error(),
|
|
"must specify one of these supported backends: mysql, sqlite3")
|
|
}
|
|
}
|
|
|
|
// If there is no DB url for non-memory backends, an error is returned.
|
|
func TestParseInvalidStorageNoDBSource(t *testing.T) {
|
|
invalids := []string{
|
|
`{"storage": {"backend": "%s"}}`,
|
|
`{"storage": {"backend": "%s", "db_url": ""}}`,
|
|
}
|
|
for _, backend := range []string{MySQLBackend, SqliteBackend} {
|
|
for _, configJSONFmt := range invalids {
|
|
configJSON := fmt.Sprintf(configJSONFmt, backend)
|
|
_, err := ParseStorage(configure(configJSON),
|
|
[]string{MySQLBackend, SqliteBackend})
|
|
assert.Error(t, err, fmt.Sprintf("'%s' should be an error", configJSON))
|
|
assert.Contains(t, err.Error(),
|
|
fmt.Sprintf("must provide a non-empty database source for %s", backend))
|
|
}
|
|
}
|
|
}
|
|
|
|
// If a memory storage backend is specified, no DB URL is necessary for a
|
|
// successful storage parse.
|
|
func TestParseStorageMemoryStore(t *testing.T) {
|
|
config := configure(`{"storage": {"backend": "MEMORY"}}`)
|
|
expected := Storage{Backend: MemoryBackend}
|
|
|
|
store, err := ParseStorage(config, []string{MySQLBackend, MemoryBackend})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *store)
|
|
}
|
|
|
|
// A supported backend with DB source will be successfully parsed.
|
|
func TestParseStorageDBStore(t *testing.T) {
|
|
config := configure(`{
|
|
"storage": {
|
|
"backend": "MySQL",
|
|
"db_url": "username:passord@tcp(hostname:1234)/dbname"
|
|
}
|
|
}`)
|
|
|
|
expected := Storage{
|
|
Backend: "mysql",
|
|
Source: "username:passord@tcp(hostname:1234)/dbname",
|
|
}
|
|
|
|
store, err := ParseStorage(config, []string{"mysql"})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *store)
|
|
}
|
|
|
|
func TestParseStorageWithEnvironmentVariables(t *testing.T) {
|
|
config := configure(`{
|
|
"storage": {
|
|
"db_url": "username:passord@tcp(hostname:1234)/dbname"
|
|
}
|
|
}`)
|
|
|
|
vars := map[string]string{"STORAGE_BACKEND": "MySQL"}
|
|
setupEnvironmentVariables(t, vars)
|
|
defer cleanupEnvironmentVariables(t, vars)
|
|
|
|
expected := Storage{
|
|
Backend: "mysql",
|
|
Source: "username:passord@tcp(hostname:1234)/dbname",
|
|
}
|
|
|
|
store, err := ParseStorage(config, []string{"mysql"})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *store)
|
|
}
|
|
|
|
// If TLS is required and the parameters are missing, an error is returned
|
|
func TestParseTLSNoTLSWhenRequired(t *testing.T) {
|
|
invalids := []string{
|
|
`{"server": {"tls_cert_file": "path/to/cert"}}`,
|
|
`{"server": {"tls_key_file": "path/to/key"}}`,
|
|
}
|
|
for _, configJSON := range invalids {
|
|
_, err := ParseServerTLS(configure(configJSON), true)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(),
|
|
"both the TLS certificate and key are mandatory")
|
|
}
|
|
}
|
|
|
|
// If TLS is not and the cert/key are partially provided, an error is returned
|
|
func TestParseTLSPartialTLS(t *testing.T) {
|
|
invalids := []string{
|
|
`{"server": {"tls_cert_file": "path/to/cert"}}`,
|
|
`{"server": {"tls_key_file": "path/to/key"}}`,
|
|
}
|
|
for _, configJSON := range invalids {
|
|
_, err := ParseServerTLS(configure(configJSON), false)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(),
|
|
"either include both a cert and key file, or neither to disable TLS")
|
|
}
|
|
}
|
|
|
|
func TestParseTLSNoTLSNotRequired(t *testing.T) {
|
|
config := configure(`{
|
|
"server": {}
|
|
}`)
|
|
|
|
tlsOpts, err := ParseServerTLS(config, false)
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, tlsOpts)
|
|
}
|
|
|
|
func TestParseTLSWithTLS(t *testing.T) {
|
|
config := configure(`{
|
|
"server": {
|
|
"tls_cert_file": "path/to/cert",
|
|
"tls_key_file": "path/to/key",
|
|
"client_ca_file": "path/to/clientca"
|
|
}
|
|
}`)
|
|
|
|
expected := ServerTLSOpts{
|
|
ServerCertFile: "path/to/cert",
|
|
ServerKeyFile: "path/to/key",
|
|
ClientCAFile: "path/to/clientca",
|
|
}
|
|
|
|
tlsOpts, err := ParseServerTLS(config, false)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *tlsOpts)
|
|
}
|
|
|
|
func TestParseTLSWithTLSRelativeToConfigFile(t *testing.T) {
|
|
config := configure(`{
|
|
"server": {
|
|
"tls_cert_file": "path/to/cert",
|
|
"tls_key_file": "/abspath/to/key",
|
|
"client_ca_file": ""
|
|
}
|
|
}`)
|
|
config.SetConfigFile("/opt/me.json")
|
|
|
|
expected := ServerTLSOpts{
|
|
ServerCertFile: "/opt/path/to/cert",
|
|
ServerKeyFile: "/abspath/to/key",
|
|
ClientCAFile: "",
|
|
}
|
|
|
|
tlsOpts, err := ParseServerTLS(config, false)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *tlsOpts)
|
|
}
|
|
|
|
func TestParseTLSWithEnvironmentVariables(t *testing.T) {
|
|
config := configure(`{
|
|
"server": {
|
|
"tls_cert_file": "path/to/cert",
|
|
"client_ca_file": "nosuchfile"
|
|
}
|
|
}`)
|
|
|
|
vars := map[string]string{
|
|
"SERVER_TLS_KEY_FILE": "path/to/key",
|
|
"SERVER_CLIENT_CA_FILE": "path/to/clientca",
|
|
}
|
|
setupEnvironmentVariables(t, vars)
|
|
defer cleanupEnvironmentVariables(t, vars)
|
|
|
|
expected := ServerTLSOpts{
|
|
ServerCertFile: "path/to/cert",
|
|
ServerKeyFile: "path/to/key",
|
|
ClientCAFile: "path/to/clientca",
|
|
}
|
|
|
|
tlsOpts, err := ParseServerTLS(config, true)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expected, *tlsOpts)
|
|
}
|
|
|
|
func TestParseViperWithInvalidFile(t *testing.T) {
|
|
v := viper.New()
|
|
SetupViper(v, envPrefix)
|
|
|
|
err := ParseViper(v, "Chronicle_Of_Dark_Secrets.json")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "Could not read config")
|
|
}
|
|
|
|
func TestParseViperWithValidFile(t *testing.T) {
|
|
file, err := os.Create("/tmp/Chronicle_Of_Dark_Secrets.json")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(file.Name())
|
|
|
|
file.WriteString(`{"logging": {"level": "debug"}}`)
|
|
|
|
v := viper.New()
|
|
SetupViper(v, envPrefix)
|
|
|
|
err = ParseViper(v, "/tmp/Chronicle_Of_Dark_Secrets.json")
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "debug", v.GetString("logging.level"))
|
|
}
|