2018-02-05 21:05:59 +00:00
package opts // import "github.com/docker/docker/opts"
2013-12-02 22:33:33 +00:00
import (
2015-05-04 21:39:48 +00:00
"fmt"
2015-02-09 14:59:05 +00:00
"strings"
2013-12-02 22:33:33 +00:00
"testing"
2020-02-12 04:03:35 +00:00
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
2013-12-02 22:33:33 +00:00
)
2014-07-09 21:47:55 +00:00
func TestValidateIPAddress ( t * testing . T ) {
2023-11-11 14:28:26 +00:00
tests := [ ] struct {
doc string
input string
expectedOut string
expectedErr string
} {
{
doc : "IPv4 loopback" ,
input : ` 127.0.0.1 ` ,
expectedOut : ` 127.0.0.1 ` ,
} ,
{
doc : "IPv4 loopback with whitespace" ,
input : ` 127.0.0.1 ` ,
expectedOut : ` 127.0.0.1 ` ,
} ,
{
doc : "IPv6 loopback long form" ,
input : ` 0:0:0:0:0:0:0:1 ` ,
expectedOut : ` ::1 ` ,
} ,
{
doc : "IPv6 loopback" ,
input : ` ::1 ` ,
expectedOut : ` ::1 ` ,
} ,
{
doc : "IPv6 loopback with whitespace" ,
input : ` ::1 ` ,
expectedOut : ` ::1 ` ,
} ,
{
doc : "IPv6 lowercase" ,
input : ` 2001:db8::68 ` ,
expectedOut : ` 2001:db8::68 ` ,
} ,
{
doc : "IPv6 uppercase" ,
input : ` 2001:DB8::68 ` ,
expectedOut : ` 2001:db8::68 ` ,
} ,
{
doc : "IPv6 with brackets" ,
input : ` [::1] ` ,
expectedErr : ` IP address is not correctly formatted: [::1] ` ,
} ,
{
doc : "IPv4 partial" ,
input : ` 127 ` ,
expectedErr : ` IP address is not correctly formatted: 127 ` ,
} ,
{
doc : "random invalid string" ,
input : ` random invalid string ` ,
expectedErr : ` IP address is not correctly formatted: random invalid string ` ,
} ,
2013-12-02 22:33:33 +00:00
}
2023-11-11 14:28:26 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . input , func ( t * testing . T ) {
actualOut , actualErr := ValidateIPAddress ( tc . input )
assert . Check ( t , is . Equal ( tc . expectedOut , actualOut ) )
if tc . expectedErr == "" {
assert . Check ( t , actualErr )
} else {
assert . Check ( t , is . Error ( actualErr , tc . expectedErr ) )
}
} )
2013-12-02 22:33:33 +00:00
}
}
2014-02-07 16:48:14 +00:00
2015-05-04 21:39:48 +00:00
func TestMapOpts ( t * testing . T ) {
tmpMap := make ( map [ string ] string )
2015-05-05 04:18:28 +00:00
o := NewMapOpts ( tmpMap , logOptsValidator )
2015-05-04 21:39:48 +00:00
o . Set ( "max-size=1" )
if o . String ( ) != "map[max-size:1]" {
t . Errorf ( "%s != [map[max-size:1]" , o . String ( ) )
}
o . Set ( "max-file=2" )
if len ( tmpMap ) != 2 {
t . Errorf ( "map length %d != 2" , len ( tmpMap ) )
}
if tmpMap [ "max-file" ] != "2" {
t . Errorf ( "max-file = %s != 2" , tmpMap [ "max-file" ] )
}
if tmpMap [ "max-size" ] != "1" {
t . Errorf ( "max-size = %s != 1" , tmpMap [ "max-size" ] )
}
if o . Set ( "dummy-val=3" ) == nil {
2016-11-14 09:01:17 +00:00
t . Error ( "validator is not being called" )
2015-05-04 21:39:48 +00:00
}
}
2015-07-12 08:33:30 +00:00
func TestListOptsWithoutValidator ( t * testing . T ) {
2014-08-10 01:13:44 +00:00
o := NewListOpts ( nil )
o . Set ( "foo" )
2014-10-07 01:54:52 +00:00
if o . String ( ) != "[foo]" {
t . Errorf ( "%s != [foo]" , o . String ( ) )
}
o . Set ( "bar" )
if o . Len ( ) != 2 {
t . Errorf ( "%d != 2" , o . Len ( ) )
}
2015-07-12 08:33:30 +00:00
o . Set ( "bar" )
if o . Len ( ) != 3 {
t . Errorf ( "%d != 3" , o . Len ( ) )
}
2014-10-07 01:54:52 +00:00
if ! o . Get ( "bar" ) {
2023-07-05 10:24:11 +00:00
t . Error ( ` o.Get("bar") == false ` )
2014-10-07 01:54:52 +00:00
}
if o . Get ( "baz" ) {
2023-07-05 10:24:11 +00:00
t . Error ( ` o.Get("baz") == true ` )
2014-10-07 01:54:52 +00:00
}
o . Delete ( "foo" )
2015-07-12 08:33:30 +00:00
if o . String ( ) != "[bar bar]" {
t . Errorf ( "%s != [bar bar]" , o . String ( ) )
}
listOpts := o . GetAll ( )
if len ( listOpts ) != 2 || listOpts [ 0 ] != "bar" || listOpts [ 1 ] != "bar" {
t . Errorf ( "Expected [[bar bar]], got [%v]" , listOpts )
2014-10-07 01:54:52 +00:00
}
2015-07-12 08:33:30 +00:00
mapListOpts := o . GetMap ( )
if len ( mapListOpts ) != 1 {
t . Errorf ( "Expected [map[bar:{}]], got [%v]" , mapListOpts )
}
2014-08-10 01:13:44 +00:00
}
2015-07-12 08:33:30 +00:00
func TestListOptsWithValidator ( t * testing . T ) {
// Re-using logOptsvalidator (used by MapOpts)
o := NewListOpts ( logOptsValidator )
o . Set ( "foo" )
2017-03-31 01:35:04 +00:00
if o . String ( ) != "" {
t . Errorf ( ` %s != "" ` , o . String ( ) )
2015-07-12 08:33:30 +00:00
}
o . Set ( "foo=bar" )
2017-03-31 01:35:04 +00:00
if o . String ( ) != "" {
t . Errorf ( ` %s != "" ` , o . String ( ) )
2015-07-12 08:33:30 +00:00
}
o . Set ( "max-file=2" )
if o . Len ( ) != 1 {
t . Errorf ( "%d != 1" , o . Len ( ) )
}
if ! o . Get ( "max-file=2" ) {
2023-07-05 10:24:11 +00:00
t . Error ( ` o.Get("max-file=2") == false ` )
2015-07-12 08:33:30 +00:00
}
if o . Get ( "baz" ) {
2023-07-05 10:24:11 +00:00
t . Error ( ` o.Get("baz") == true ` )
2015-07-12 08:33:30 +00:00
}
o . Delete ( "max-file=2" )
2017-03-31 01:35:04 +00:00
if o . String ( ) != "" {
t . Errorf ( ` %s != "" ` , o . String ( ) )
2015-07-12 08:33:30 +00:00
}
}
func TestValidateDNSSearch ( t * testing . T ) {
2014-02-07 16:48:14 +00:00
valid := [ ] string {
2014-06-26 11:03:23 +00:00
` . ` ,
2014-02-07 16:48:14 +00:00
` a ` ,
` a. ` ,
` 1.foo ` ,
` 17.foo ` ,
` foo.bar ` ,
` foo.bar.baz ` ,
` foo.bar. ` ,
` foo.bar.baz ` ,
` foo1.bar2 ` ,
` foo1.bar2.baz ` ,
` 1foo.2bar. ` ,
` 1foo.2bar.baz ` ,
` foo-1.bar-2 ` ,
` foo-1.bar-2.baz ` ,
` foo-1.bar-2. ` ,
` foo-1.bar-2.baz ` ,
` 1-foo.2-bar ` ,
` 1-foo.2-bar.baz ` ,
` 1-foo.2-bar. ` ,
` 1-foo.2-bar.baz ` ,
}
invalid := [ ] string {
` ` ,
2014-06-26 11:03:23 +00:00
` ` ,
` ` ,
2014-02-07 16:48:14 +00:00
` 17 ` ,
` 17. ` ,
` .17 ` ,
` 17-. ` ,
` 17-.foo ` ,
` .foo ` ,
` foo-.bar ` ,
` -foo.bar ` ,
` foo.bar- ` ,
` foo.bar-.baz ` ,
` foo.-bar ` ,
` foo.-bar.baz ` ,
2017-05-21 23:24:07 +00:00
` foo.bar.baz.this.should.fail.on.long.name.because.it.is.longer.thanitshouldbethis.should.fail.on.long.name.because.it.is.longer.thanitshouldbethis.should.fail.on.long.name.because.it.is.longer.thanitshouldbethis.should.fail.on.long.name.because.it.is.longer.thanitshouldbe ` ,
2014-02-07 16:48:14 +00:00
}
for _ , domain := range valid {
2015-07-12 08:33:30 +00:00
if ret , err := ValidateDNSSearch ( domain ) ; err != nil || ret == "" {
t . Fatalf ( "ValidateDNSSearch(`" + domain + "`) got %s %s" , ret , err )
2014-02-07 16:48:14 +00:00
}
}
for _ , domain := range invalid {
2015-07-12 08:33:30 +00:00
if ret , err := ValidateDNSSearch ( domain ) ; err == nil || ret != "" {
t . Fatalf ( "ValidateDNSSearch(`" + domain + "`) got %s %s" , ret , err )
2014-02-07 16:48:14 +00:00
}
2015-07-12 08:33:30 +00:00
}
}
func TestValidateLabel ( t * testing . T ) {
2020-02-12 04:03:35 +00:00
testCases := [ ] struct {
name string
label string
expectedResult string
expectedErr string
} {
{
name : "lable with bad attribute format" ,
label : "label" ,
expectedErr : "bad attribute format: label" ,
} ,
{
name : "label with general format" ,
label : "key1=value1" ,
expectedResult : "key1=value1" ,
} ,
{
name : "label with more than one =" ,
label : "key1=value1=value2" ,
expectedResult : "key1=value1=value2" ,
} ,
{
name : "label with one more" ,
label : "key1=value1=value2=value3" ,
expectedResult : "key1=value1=value2=value3" ,
} ,
{
name : "label with no reserved com.docker.*" ,
label : "com.dockerpsychnotreserved.label=value" ,
expectedResult : "com.dockerpsychnotreserved.label=value" ,
} ,
{
name : "label with no reserved io.docker.*" ,
label : "io.dockerproject.not=reserved" ,
expectedResult : "io.dockerproject.not=reserved" ,
} ,
{
name : "label with no reserved org.dockerproject.*" ,
label : "org.docker.not=reserved" ,
expectedResult : "org.docker.not=reserved" ,
} ,
{
name : "label with reserved com.docker.*" ,
label : "com.docker.feature=enabled" ,
expectedErr : "label com.docker.feature=enabled is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
{
name : "label with reserved upcase com.docker.* " ,
label : "COM.docker.feature=enabled" ,
expectedErr : "label COM.docker.feature=enabled is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
{
name : "label with reserved io.docker.*" ,
label : "io.docker.configuration=0" ,
expectedErr : "label io.docker.configuration=0 is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
{
name : "label with reserved upcase io.docker.*" ,
label : "io.DOCKER.CONFIGURATion=0" ,
expectedErr : "label io.DOCKER.CONFIGURATion=0 is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
{
name : "label with reserved org.dockerproject.*" ,
label : "org.dockerproject.setting=on" ,
expectedErr : "label org.dockerproject.setting=on is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
{
name : "label with reserved upcase org.dockerproject.*" ,
label : "Org.Dockerproject.Setting=on" ,
expectedErr : "label Org.Dockerproject.Setting=on is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use" ,
} ,
2015-07-12 08:33:30 +00:00
}
2020-02-12 04:03:35 +00:00
for _ , testCase := range testCases {
testCase := testCase
t . Run ( testCase . name , func ( t * testing . T ) {
result , err := ValidateLabel ( testCase . label )
if testCase . expectedErr != "" {
assert . Error ( t , err , testCase . expectedErr )
} else {
assert . NilError ( t , err )
}
if testCase . expectedResult != "" {
assert . Check ( t , is . Equal ( result , testCase . expectedResult ) )
}
} )
2015-07-12 08:33:30 +00:00
}
}
2015-05-04 21:39:48 +00:00
func logOptsValidator ( val string ) ( string , error ) {
allowedKeys := map [ string ] string { "max-size" : "1" , "max-file" : "2" }
vals := strings . Split ( val , "=" )
if allowedKeys [ vals [ 0 ] ] != "" {
return val , nil
}
return "" , fmt . Errorf ( "invalid key %s" , vals [ 0 ] )
}
2015-12-10 23:35:10 +00:00
func TestNamedListOpts ( t * testing . T ) {
var v [ ] string
o := NewNamedListOptsRef ( "foo-name" , & v , nil )
o . Set ( "foo" )
if o . String ( ) != "[foo]" {
t . Errorf ( "%s != [foo]" , o . String ( ) )
}
if o . Name ( ) != "foo-name" {
t . Errorf ( "%s != foo-name" , o . Name ( ) )
}
if len ( v ) != 1 {
t . Errorf ( "expected foo to be in the values, got %v" , v )
}
}
func TestNamedMapOpts ( t * testing . T ) {
tmpMap := make ( map [ string ] string )
o := NewNamedMapOpts ( "max-name" , tmpMap , nil )
o . Set ( "max-size=1" )
if o . String ( ) != "map[max-size:1]" {
t . Errorf ( "%s != [map[max-size:1]" , o . String ( ) )
}
if o . Name ( ) != "max-name" {
t . Errorf ( "%s != max-name" , o . Name ( ) )
}
if _ , exist := tmpMap [ "max-size" ] ; ! exist {
t . Errorf ( "expected map-size to be in the values, got %v" , tmpMap )
}
}
2016-12-23 19:09:12 +00:00
func TestParseLink ( t * testing . T ) {
2022-10-31 09:28:20 +00:00
t . Run ( "name and alias" , func ( t * testing . T ) {
name , alias , err := ParseLink ( "name:alias" )
assert . Check ( t , err )
assert . Check ( t , is . Equal ( name , "name" ) )
assert . Check ( t , is . Equal ( alias , "alias" ) )
} )
t . Run ( "short format" , func ( t * testing . T ) {
name , alias , err := ParseLink ( "name" )
assert . Check ( t , err )
assert . Check ( t , is . Equal ( name , "name" ) )
assert . Check ( t , is . Equal ( alias , "name" ) )
} )
t . Run ( "empty string" , func ( t * testing . T ) {
_ , _ , err := ParseLink ( "" )
assert . Check ( t , is . Error ( err , "empty string specified for links" ) )
} )
t . Run ( "more than two colons" , func ( t * testing . T ) {
_ , _ , err := ParseLink ( "link:alias:wrong" )
assert . Check ( t , is . Error ( err , "bad format for links: link:alias:wrong" ) )
} )
t . Run ( "legacy format" , func ( t * testing . T ) {
name , alias , err := ParseLink ( "/foo:/c1/bar" )
assert . Check ( t , err )
assert . Check ( t , is . Equal ( name , "foo" ) )
assert . Check ( t , is . Equal ( alias , "bar" ) )
} )
2016-12-23 19:09:12 +00:00
}
2022-01-27 20:13:45 +00:00
func TestMapMapOpts ( t * testing . T ) {
tmpMap := make ( map [ string ] map [ string ] string )
validator := func ( val string ) ( string , error ) {
if strings . HasPrefix ( val , "invalid-key=" ) {
return "" , fmt . Errorf ( "invalid key %s" , val )
}
return val , nil
}
o := NewMapMapOpts ( tmpMap , validator )
o . Set ( "r1=k11=v11" )
assert . Check ( t , is . DeepEqual ( tmpMap , map [ string ] map [ string ] string { "r1" : { "k11" : "v11" } } ) )
o . Set ( "r2=k21=v21" )
assert . Check ( t , is . Len ( tmpMap , 2 ) )
if err := o . Set ( "invalid-syntax" ) ; err == nil {
t . Error ( "invalid mapping syntax is not being caught" )
}
if err := o . Set ( "k=invalid-syntax" ) ; err == nil {
t . Error ( "invalid value syntax is not being caught" )
}
o . Set ( "r1=k12=v12" )
assert . Check ( t , is . DeepEqual ( tmpMap [ "r1" ] , map [ string ] string { "k11" : "v11" , "k12" : "v12" } ) )
2023-07-05 10:24:11 +00:00
if o . Set ( ` invalid-key= { "k":"v"} ` ) == nil {
2022-01-27 20:13:45 +00:00
t . Error ( "validator is not being called" )
}
}