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