github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/opts/opts_test.go (about)

     1  package opts // import "github.com/demonoid81/moby/opts"
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"gotest.tools/v3/assert"
     9  	is "gotest.tools/v3/assert/cmp"
    10  )
    11  
    12  func TestValidateIPAddress(t *testing.T) {
    13  	if ret, err := ValidateIPAddress(`1.2.3.4`); err != nil || ret == "" {
    14  		t.Fatalf("ValidateIPAddress(`1.2.3.4`) got %s %s", ret, err)
    15  	}
    16  
    17  	if ret, err := ValidateIPAddress(`127.0.0.1`); err != nil || ret == "" {
    18  		t.Fatalf("ValidateIPAddress(`127.0.0.1`) got %s %s", ret, err)
    19  	}
    20  
    21  	if ret, err := ValidateIPAddress(`::1`); err != nil || ret == "" {
    22  		t.Fatalf("ValidateIPAddress(`::1`) got %s %s", ret, err)
    23  	}
    24  
    25  	if ret, err := ValidateIPAddress(`127`); err == nil || ret != "" {
    26  		t.Fatalf("ValidateIPAddress(`127`) got %s %s", ret, err)
    27  	}
    28  
    29  	if ret, err := ValidateIPAddress(`random invalid string`); err == nil || ret != "" {
    30  		t.Fatalf("ValidateIPAddress(`random invalid string`) got %s %s", ret, err)
    31  	}
    32  
    33  }
    34  
    35  func TestMapOpts(t *testing.T) {
    36  	tmpMap := make(map[string]string)
    37  	o := NewMapOpts(tmpMap, logOptsValidator)
    38  	o.Set("max-size=1")
    39  	if o.String() != "map[max-size:1]" {
    40  		t.Errorf("%s != [map[max-size:1]", o.String())
    41  	}
    42  
    43  	o.Set("max-file=2")
    44  	if len(tmpMap) != 2 {
    45  		t.Errorf("map length %d != 2", len(tmpMap))
    46  	}
    47  
    48  	if tmpMap["max-file"] != "2" {
    49  		t.Errorf("max-file = %s != 2", tmpMap["max-file"])
    50  	}
    51  
    52  	if tmpMap["max-size"] != "1" {
    53  		t.Errorf("max-size = %s != 1", tmpMap["max-size"])
    54  	}
    55  	if o.Set("dummy-val=3") == nil {
    56  		t.Error("validator is not being called")
    57  	}
    58  }
    59  
    60  func TestListOptsWithoutValidator(t *testing.T) {
    61  	o := NewListOpts(nil)
    62  	o.Set("foo")
    63  	if o.String() != "[foo]" {
    64  		t.Errorf("%s != [foo]", o.String())
    65  	}
    66  	o.Set("bar")
    67  	if o.Len() != 2 {
    68  		t.Errorf("%d != 2", o.Len())
    69  	}
    70  	o.Set("bar")
    71  	if o.Len() != 3 {
    72  		t.Errorf("%d != 3", o.Len())
    73  	}
    74  	if !o.Get("bar") {
    75  		t.Error("o.Get(\"bar\") == false")
    76  	}
    77  	if o.Get("baz") {
    78  		t.Error("o.Get(\"baz\") == true")
    79  	}
    80  	o.Delete("foo")
    81  	if o.String() != "[bar bar]" {
    82  		t.Errorf("%s != [bar bar]", o.String())
    83  	}
    84  	listOpts := o.GetAll()
    85  	if len(listOpts) != 2 || listOpts[0] != "bar" || listOpts[1] != "bar" {
    86  		t.Errorf("Expected [[bar bar]], got [%v]", listOpts)
    87  	}
    88  	mapListOpts := o.GetMap()
    89  	if len(mapListOpts) != 1 {
    90  		t.Errorf("Expected [map[bar:{}]], got [%v]", mapListOpts)
    91  	}
    92  
    93  }
    94  
    95  func TestListOptsWithValidator(t *testing.T) {
    96  	// Re-using logOptsvalidator (used by MapOpts)
    97  	o := NewListOpts(logOptsValidator)
    98  	o.Set("foo")
    99  	if o.String() != "" {
   100  		t.Errorf(`%s != ""`, o.String())
   101  	}
   102  	o.Set("foo=bar")
   103  	if o.String() != "" {
   104  		t.Errorf(`%s != ""`, o.String())
   105  	}
   106  	o.Set("max-file=2")
   107  	if o.Len() != 1 {
   108  		t.Errorf("%d != 1", o.Len())
   109  	}
   110  	if !o.Get("max-file=2") {
   111  		t.Error("o.Get(\"max-file=2\") == false")
   112  	}
   113  	if o.Get("baz") {
   114  		t.Error("o.Get(\"baz\") == true")
   115  	}
   116  	o.Delete("max-file=2")
   117  	if o.String() != "" {
   118  		t.Errorf(`%s != ""`, o.String())
   119  	}
   120  }
   121  
   122  func TestValidateDNSSearch(t *testing.T) {
   123  	valid := []string{
   124  		`.`,
   125  		`a`,
   126  		`a.`,
   127  		`1.foo`,
   128  		`17.foo`,
   129  		`foo.bar`,
   130  		`foo.bar.baz`,
   131  		`foo.bar.`,
   132  		`foo.bar.baz`,
   133  		`foo1.bar2`,
   134  		`foo1.bar2.baz`,
   135  		`1foo.2bar.`,
   136  		`1foo.2bar.baz`,
   137  		`foo-1.bar-2`,
   138  		`foo-1.bar-2.baz`,
   139  		`foo-1.bar-2.`,
   140  		`foo-1.bar-2.baz`,
   141  		`1-foo.2-bar`,
   142  		`1-foo.2-bar.baz`,
   143  		`1-foo.2-bar.`,
   144  		`1-foo.2-bar.baz`,
   145  	}
   146  
   147  	invalid := []string{
   148  		``,
   149  		` `,
   150  		`  `,
   151  		`17`,
   152  		`17.`,
   153  		`.17`,
   154  		`17-.`,
   155  		`17-.foo`,
   156  		`.foo`,
   157  		`foo-.bar`,
   158  		`-foo.bar`,
   159  		`foo.bar-`,
   160  		`foo.bar-.baz`,
   161  		`foo.-bar`,
   162  		`foo.-bar.baz`,
   163  		`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`,
   164  	}
   165  
   166  	for _, domain := range valid {
   167  		if ret, err := ValidateDNSSearch(domain); err != nil || ret == "" {
   168  			t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err)
   169  		}
   170  	}
   171  
   172  	for _, domain := range invalid {
   173  		if ret, err := ValidateDNSSearch(domain); err == nil || ret != "" {
   174  			t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err)
   175  		}
   176  	}
   177  }
   178  
   179  func TestValidateLabel(t *testing.T) {
   180  	testCases := []struct {
   181  		name           string
   182  		label          string
   183  		expectedResult string
   184  		expectedErr    string
   185  	}{
   186  		{
   187  			name:        "lable with bad attribute format",
   188  			label:       "label",
   189  			expectedErr: "bad attribute format: label",
   190  		},
   191  		{
   192  			name:           "label with general format",
   193  			label:          "key1=value1",
   194  			expectedResult: "key1=value1",
   195  		},
   196  		{
   197  			name:           "label with more than one =",
   198  			label:          "key1=value1=value2",
   199  			expectedResult: "key1=value1=value2",
   200  		},
   201  		{
   202  			name:           "label with one more",
   203  			label:          "key1=value1=value2=value3",
   204  			expectedResult: "key1=value1=value2=value3",
   205  		},
   206  		{
   207  			name:           "label with no reserved com.docker.*",
   208  			label:          "com.dockerpsychnotreserved.label=value",
   209  			expectedResult: "com.dockerpsychnotreserved.label=value",
   210  		},
   211  		{
   212  			name:           "label with no reserved io.docker.*",
   213  			label:          "io.dockerproject.not=reserved",
   214  			expectedResult: "io.dockerproject.not=reserved",
   215  		},
   216  		{
   217  			name:           "label with no reserved org.dockerproject.*",
   218  			label:          "org.docker.not=reserved",
   219  			expectedResult: "org.docker.not=reserved",
   220  		},
   221  		{
   222  			name:        "label with reserved com.docker.*",
   223  			label:       "com.docker.feature=enabled",
   224  			expectedErr: "label com.docker.feature=enabled is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   225  		},
   226  		{
   227  			name:        "label with reserved upcase com.docker.* ",
   228  			label:       "COM.docker.feature=enabled",
   229  			expectedErr: "label COM.docker.feature=enabled is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   230  		},
   231  		{
   232  			name:        "label with reserved io.docker.*",
   233  			label:       "io.docker.configuration=0",
   234  			expectedErr: "label io.docker.configuration=0 is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   235  		},
   236  		{
   237  			name:        "label with reserved upcase io.docker.*",
   238  			label:       "io.DOCKER.CONFIGURATion=0",
   239  			expectedErr: "label io.DOCKER.CONFIGURATion=0 is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   240  		},
   241  		{
   242  			name:        "label with reserved org.dockerproject.*",
   243  			label:       "org.dockerproject.setting=on",
   244  			expectedErr: "label org.dockerproject.setting=on is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   245  		},
   246  		{
   247  			name:        "label with reserved upcase org.dockerproject.*",
   248  			label:       "Org.Dockerproject.Setting=on",
   249  			expectedErr: "label Org.Dockerproject.Setting=on is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
   250  		},
   251  	}
   252  
   253  	for _, testCase := range testCases {
   254  		testCase := testCase
   255  		t.Run(testCase.name, func(t *testing.T) {
   256  			result, err := ValidateLabel(testCase.label)
   257  
   258  			if testCase.expectedErr != "" {
   259  				assert.Error(t, err, testCase.expectedErr)
   260  			} else {
   261  				assert.NilError(t, err)
   262  			}
   263  			if testCase.expectedResult != "" {
   264  				assert.Check(t, is.Equal(result, testCase.expectedResult))
   265  			}
   266  		})
   267  
   268  	}
   269  }
   270  
   271  func logOptsValidator(val string) (string, error) {
   272  	allowedKeys := map[string]string{"max-size": "1", "max-file": "2"}
   273  	vals := strings.Split(val, "=")
   274  	if allowedKeys[vals[0]] != "" {
   275  		return val, nil
   276  	}
   277  	return "", fmt.Errorf("invalid key %s", vals[0])
   278  }
   279  
   280  func TestNamedListOpts(t *testing.T) {
   281  	var v []string
   282  	o := NewNamedListOptsRef("foo-name", &v, nil)
   283  
   284  	o.Set("foo")
   285  	if o.String() != "[foo]" {
   286  		t.Errorf("%s != [foo]", o.String())
   287  	}
   288  	if o.Name() != "foo-name" {
   289  		t.Errorf("%s != foo-name", o.Name())
   290  	}
   291  	if len(v) != 1 {
   292  		t.Errorf("expected foo to be in the values, got %v", v)
   293  	}
   294  }
   295  
   296  func TestNamedMapOpts(t *testing.T) {
   297  	tmpMap := make(map[string]string)
   298  	o := NewNamedMapOpts("max-name", tmpMap, nil)
   299  
   300  	o.Set("max-size=1")
   301  	if o.String() != "map[max-size:1]" {
   302  		t.Errorf("%s != [map[max-size:1]", o.String())
   303  	}
   304  	if o.Name() != "max-name" {
   305  		t.Errorf("%s != max-name", o.Name())
   306  	}
   307  	if _, exist := tmpMap["max-size"]; !exist {
   308  		t.Errorf("expected map-size to be in the values, got %v", tmpMap)
   309  	}
   310  }
   311  
   312  func TestParseLink(t *testing.T) {
   313  	name, alias, err := ParseLink("name:alias")
   314  	if err != nil {
   315  		t.Fatalf("Expected not to error out on a valid name:alias format but got: %v", err)
   316  	}
   317  	if name != "name" {
   318  		t.Fatalf("Link name should have been name, got %s instead", name)
   319  	}
   320  	if alias != "alias" {
   321  		t.Fatalf("Link alias should have been alias, got %s instead", alias)
   322  	}
   323  	// short format definition
   324  	name, alias, err = ParseLink("name")
   325  	if err != nil {
   326  		t.Fatalf("Expected not to error out on a valid name only format but got: %v", err)
   327  	}
   328  	if name != "name" {
   329  		t.Fatalf("Link name should have been name, got %s instead", name)
   330  	}
   331  	if alias != "name" {
   332  		t.Fatalf("Link alias should have been name, got %s instead", alias)
   333  	}
   334  	// empty string link definition is not allowed
   335  	if _, _, err := ParseLink(""); err == nil || !strings.Contains(err.Error(), "empty string specified for links") {
   336  		t.Fatalf("Expected error 'empty string specified for links' but got: %v", err)
   337  	}
   338  	// more than two colons are not allowed
   339  	if _, _, err := ParseLink("link:alias:wrong"); err == nil || !strings.Contains(err.Error(), "bad format for links: link:alias:wrong") {
   340  		t.Fatalf("Expected error 'bad format for links: link:alias:wrong' but got: %v", err)
   341  	}
   342  }