361 lines
9.7 KiB
Go
361 lines
9.7 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func testValidSchema(t *testing.T, serviceMap RawServiceMap) {
|
|
err := validate(serviceMap, "v1")
|
|
assert.Nil(t, err)
|
|
|
|
for name, service := range serviceMap {
|
|
err := validateServiceConstraints(service, name)
|
|
assert.Nil(t, err)
|
|
}
|
|
}
|
|
|
|
func testInvalidSchema(t *testing.T, serviceMap RawServiceMap, errMsgs []string, errCount int) {
|
|
var combinedErrMsg bytes.Buffer
|
|
|
|
err := validate(serviceMap, "v2")
|
|
if err != nil {
|
|
combinedErrMsg.WriteString(err.Error())
|
|
combinedErrMsg.WriteRune('\n')
|
|
}
|
|
|
|
for name, service := range serviceMap {
|
|
err := validateServiceConstraints(service, name)
|
|
if err != nil {
|
|
combinedErrMsg.WriteString(err.Error())
|
|
combinedErrMsg.WriteRune('\n')
|
|
}
|
|
}
|
|
|
|
for _, errMsg := range errMsgs {
|
|
assert.True(t, strings.Contains(combinedErrMsg.String(), errMsg))
|
|
}
|
|
|
|
// gojsonschema has bugs that can cause extraneous errors
|
|
// This makes sure we don't have more errors than expected
|
|
assert.True(t, strings.Count(combinedErrMsg.String(), "\n") == errCount)
|
|
}
|
|
|
|
func TestInvalidServiceNames(t *testing.T) {
|
|
invalidServiceNames := []string{"?not?allowed", " ", "", "!", "/"}
|
|
|
|
for _, invalidServiceName := range invalidServiceNames {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
invalidServiceName: map[string]interface{}{
|
|
"image": "busybox",
|
|
},
|
|
}, []string{fmt.Sprintf("Invalid service name '%s' - only [a-zA-Z0-9\\._\\-] characters are allowed", invalidServiceName)}, 1)
|
|
}
|
|
}
|
|
|
|
func TestValidServiceNames(t *testing.T) {
|
|
validServiceNames := []string{"_", "-", ".__.", "_what-up.", "what_.up----", "whatup"}
|
|
|
|
for _, validServiceName := range validServiceNames {
|
|
testValidSchema(t, RawServiceMap{
|
|
validServiceName: map[string]interface{}{
|
|
"image": "busybox",
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
/*
|
|
func TestConfigInvalidPorts(t *testing.T) {
|
|
portsValues := []interface{}{
|
|
map[string]interface{}{
|
|
"1": "8000",
|
|
},
|
|
false,
|
|
0,
|
|
"8000",
|
|
}
|
|
|
|
for _, portsValue := range portsValues {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"ports": portsValue,
|
|
},
|
|
}, []string{"Service 'web' configuration key 'ports' contains an invalid type, it should be an array"}, 1)
|
|
}
|
|
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"ports": []interface{}{
|
|
"8000",
|
|
"8000",
|
|
},
|
|
},
|
|
}, []string{"Service 'web' configuration key 'ports' value [8000 8000] has non-unique elements"}, 1)
|
|
}
|
|
*/
|
|
|
|
/*
|
|
func TestConfigValidPorts(t *testing.T) {
|
|
portsValues := []interface{}{
|
|
[]interface{}{"8000", "9000"},
|
|
[]interface{}{"8000"},
|
|
[]interface{}{8000},
|
|
[]interface{}{"127.0.0.1::8000"},
|
|
[]interface{}{"49153-49154:3002-3003"},
|
|
}
|
|
|
|
for _, portsValue := range portsValues {
|
|
testValidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"ports": portsValue,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
*/
|
|
|
|
func TestConfigHint(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
"privilege": "something",
|
|
},
|
|
}, []string{"Unsupported config option for foo service: 'privilege'"}, 1)
|
|
}
|
|
|
|
func TestTypeShouldBeAnArray(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
"links": "an_link",
|
|
},
|
|
}, []string{"Service 'foo' configuration key 'links' contains an invalid type, it should be an array"}, 1)
|
|
}
|
|
|
|
func TestInvalidTypeWithMultipleValidTypes(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"mem_limit": []interface{}{
|
|
"array_elem",
|
|
},
|
|
},
|
|
}, []string{"Unsupported config option for web service: 'mem_limit'"}, 1)
|
|
}
|
|
|
|
func TestInvalidNotUniqueItems(t *testing.T) {
|
|
// Test property with array as only valid type
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
"devices": []string{
|
|
"/dev/foo:/dev/foo",
|
|
"/dev/foo:/dev/foo",
|
|
},
|
|
},
|
|
}, []string{"Unsupported config option for foo service: 'devices'"}, 1)
|
|
|
|
// Test property with multiple valid types
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
"environment": []string{
|
|
"KEY=VAL",
|
|
"KEY=VAL",
|
|
},
|
|
},
|
|
}, []string{"Service 'foo' configuration key 'environment' contains non unique items, please remove duplicates from [KEY=VAL KEY=VAL]"}, 1)
|
|
}
|
|
|
|
func TestInvalidListOfStringsFormat(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"command": []interface{}{
|
|
1,
|
|
},
|
|
},
|
|
}, []string{"Service 'web' configuration key 'command' contains 1, which is an invalid type, it should be a string"}, 1)
|
|
}
|
|
|
|
func TestInvalidExtraHostsString(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"extra_hosts": "somehost:162.242.195.82",
|
|
},
|
|
}, []string{"Unsupported config option for web service: 'extra_hosts'"}, 1)
|
|
}
|
|
|
|
/*
|
|
func TestValidConfigWhichAllowsTwoTypeDefinitions(t *testing.T) {
|
|
for _, exposeValue := range []interface{}{"8000", 9000} {
|
|
testValidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"expose": []interface{}{
|
|
exposeValue,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
}
|
|
*/
|
|
|
|
func TestValidConfigOneOfStringOrList(t *testing.T) {
|
|
entrypointValues := []interface{}{
|
|
[]interface{}{
|
|
"sh",
|
|
},
|
|
"sh",
|
|
}
|
|
|
|
for _, entrypointValue := range entrypointValues {
|
|
testValidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"entrypoint": entrypointValue,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInvalidServiceProperty(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"invalid_property": "value",
|
|
},
|
|
}, []string{"Unsupported config option for web service: 'invalid_property'"}, 1)
|
|
}
|
|
|
|
func TestServiceInvalidMissingImageAndBuild(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{},
|
|
}, []string{"Service 'web' has neither an image nor a build path specified. Exactly one must be provided."}, 1)
|
|
}
|
|
|
|
func TestServiceInvalidSpecifiesImageAndBuild(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"build": ".",
|
|
},
|
|
}, []string{"Unsupported config option for web service: 'build'"}, 1)
|
|
}
|
|
|
|
func TestServiceInvalidSpecifiesImageAndDockerfile(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"web": map[string]interface{}{
|
|
"image": "busybox",
|
|
"dockerfile": "Dockerfile",
|
|
},
|
|
}, []string{"Unsupported config option for web service: 'dockerfile'"}, 1)
|
|
}
|
|
|
|
func TestInvalidServiceForMultipleErrors(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
"links": "an_type",
|
|
"environment": []string{
|
|
"KEY=VAL",
|
|
"KEY=VAL",
|
|
},
|
|
},
|
|
}, []string{
|
|
// "Service 'foo' configuration key 'ports' contains an invalid type, it should be an array",
|
|
"Service 'foo' configuration key 'links' contains an invalid type, it should be an array",
|
|
"Service 'foo' configuration key 'environment' contains non unique items, please remove duplicates from [KEY=VAL KEY=VAL]",
|
|
}, 2)
|
|
}
|
|
|
|
func TestInvalidServiceWithAdditionalProperties(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
"---": "nope",
|
|
"environment": []string{
|
|
"KEY=VAL",
|
|
"KEY=VAL",
|
|
},
|
|
},
|
|
}, []string{
|
|
// "Service 'foo' configuration key 'ports' contains an invalid type, it should be an array",
|
|
"Unsupported config option for foo service: '---'",
|
|
"Service 'foo' configuration key 'environment' contains non unique items, please remove duplicates from [KEY=VAL KEY=VAL]",
|
|
}, 2)
|
|
}
|
|
|
|
func TestMultipleInvalidServices(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo1": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
},
|
|
"foo2": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
},
|
|
}, []string{
|
|
// "Service 'foo1' configuration key 'ports' contains an invalid type, it should be an array",
|
|
// "Service 'foo2' configuration key 'ports' contains an invalid type, it should be an array",
|
|
}, 0)
|
|
}
|
|
|
|
func TestMixedInvalidServicesAndInvalidServiceNames(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
//"foo1": map[string]interface{}{
|
|
// "image": "busybox",
|
|
// "ports": "invalid_type",
|
|
// },
|
|
"???": map[string]interface{}{
|
|
"image": "busybox",
|
|
},
|
|
// "foo2": map[string]interface{}{
|
|
// "image": "busybox",
|
|
// "ports": "invalid_type",
|
|
// },
|
|
}, []string{
|
|
// "Service 'foo1' configuration key 'ports' contains an invalid type, it should be an array",
|
|
"Invalid service name '???' - only [a-zA-Z0-9\\._\\-] characters are allowed",
|
|
// "Service 'foo2' configuration key 'ports' contains an invalid type, it should be an array",
|
|
}, 1)
|
|
}
|
|
|
|
func TestMultipleInvalidServicesForMultipleErrors(t *testing.T) {
|
|
testInvalidSchema(t, RawServiceMap{
|
|
"foo1": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
"environment": []string{
|
|
"KEY=VAL",
|
|
"KEY=VAL",
|
|
},
|
|
},
|
|
"foo2": map[string]interface{}{
|
|
"image": "busybox",
|
|
// "ports": "invalid_type",
|
|
"environment": []string{
|
|
"KEY=VAL",
|
|
"KEY=VAL",
|
|
},
|
|
},
|
|
}, []string{
|
|
// "Service 'foo1' configuration key 'ports' contains an invalid type, it should be an array",
|
|
"Service 'foo1' configuration key 'environment' contains non unique items, please remove duplicates from [KEY=VAL KEY=VAL]",
|
|
// "Service 'foo2' configuration key 'ports' contains an invalid type, it should be an array",
|
|
"Service 'foo2' configuration key 'environment' contains non unique items, please remove duplicates from [KEY=VAL KEY=VAL]",
|
|
}, 2)
|
|
}
|