github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/yaml/decoder_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package yaml 18 19 import ( 20 "bufio" 21 "bytes" 22 "encoding/json" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "math/rand" 27 "reflect" 28 "strings" 29 "testing" 30 ) 31 32 func TestYAMLDecoderReadBytesLength(t *testing.T) { 33 d := `--- 34 stuff: 1 35 test-foo: 1 36 ` 37 testCases := []struct { 38 bufLen int 39 expectLen int 40 expectErr error 41 }{ 42 {len(d), len(d), nil}, 43 {len(d) + 10, len(d), nil}, 44 {len(d) - 10, len(d) - 10, io.ErrShortBuffer}, 45 } 46 47 for i, testCase := range testCases { 48 r := NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(d)))) 49 b := make([]byte, testCase.bufLen) 50 n, err := r.Read(b) 51 if err != testCase.expectErr || n != testCase.expectLen { 52 t.Fatalf("%d: unexpected body: %d / %v", i, n, err) 53 } 54 } 55 } 56 57 func TestBigYAML(t *testing.T) { 58 d := ` 59 stuff: 1 60 ` 61 maxLen := 5 * 1024 * 1024 62 bufferLen := 4 * 1024 63 // maxLen 5 M 64 dd := strings.Repeat(d, 512*1024) 65 r := NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(dd[:maxLen-1])))) 66 b := make([]byte, bufferLen) 67 n, err := r.Read(b) 68 if err != io.ErrShortBuffer { 69 t.Fatalf("expected ErrShortBuffer: %d / %v", n, err) 70 } 71 b = make([]byte, maxLen) 72 n, err = r.Read(b) 73 if err != nil { 74 t.Fatalf("expected nil: %d / %v", n, err) 75 } 76 r = NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(dd)))) 77 b = make([]byte, maxLen) 78 n, err = r.Read(b) 79 if err != bufio.ErrTooLong { 80 t.Fatalf("bufio.Scanner: token too long: %d / %v", n, err) 81 } 82 } 83 84 func TestYAMLDecoderCallsAfterErrShortBufferRestOfFrame(t *testing.T) { 85 d := `--- 86 stuff: 1 87 test-foo: 1` 88 r := NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(d)))) 89 b := make([]byte, 12) 90 n, err := r.Read(b) 91 if err != io.ErrShortBuffer || n != 12 { 92 t.Fatalf("expected ErrShortBuffer: %d / %v", n, err) 93 } 94 expected := "---\nstuff: 1" 95 if string(b) != expected { 96 t.Fatalf("expected bytes read to be: %s got: %s", expected, string(b)) 97 } 98 b = make([]byte, 13) 99 n, err = r.Read(b) 100 if err != nil || n != 13 { 101 t.Fatalf("expected nil: %d / %v", n, err) 102 } 103 expected = "\n\ttest-foo: 1" 104 if string(b) != expected { 105 t.Fatalf("expected bytes read to be: '%s' got: '%s'", expected, string(b)) 106 } 107 b = make([]byte, 15) 108 n, err = r.Read(b) 109 if err != io.EOF || n != 0 { 110 t.Fatalf("expected EOF: %d / %v", n, err) 111 } 112 } 113 114 func TestSplitYAMLDocument(t *testing.T) { 115 testCases := []struct { 116 input string 117 atEOF bool 118 expect string 119 adv int 120 }{ 121 {"foo", true, "foo", 3}, 122 {"fo", false, "", 0}, 123 124 {"---", true, "---", 3}, 125 {"---\n", true, "---\n", 4}, 126 {"---\n", false, "", 0}, 127 128 {"\n---\n", false, "", 5}, 129 {"\n---\n", true, "", 5}, 130 131 {"abc\n---\ndef", true, "abc", 8}, 132 {"def", true, "def", 3}, 133 {"", true, "", 0}, 134 } 135 for i, testCase := range testCases { 136 adv, token, err := splitYAMLDocument([]byte(testCase.input), testCase.atEOF) 137 if err != nil { 138 t.Errorf("%d: unexpected error: %v", i, err) 139 continue 140 } 141 if adv != testCase.adv { 142 t.Errorf("%d: advance did not match: %d %d", i, testCase.adv, adv) 143 } 144 if testCase.expect != string(token) { 145 t.Errorf("%d: token did not match: %q %q", i, testCase.expect, string(token)) 146 } 147 } 148 } 149 150 func TestGuessJSON(t *testing.T) { 151 if r, _, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON { 152 t.Fatalf("expected stream to be JSON") 153 } else { 154 b := make([]byte, 30) 155 n, err := r.Read(b) 156 if err != nil || n != 4 { 157 t.Fatalf("unexpected body: %d / %v", n, err) 158 } 159 if string(b[:n]) != " \n{}" { 160 t.Fatalf("unexpected body: %q", string(b[:n])) 161 } 162 } 163 } 164 165 func TestScanYAML(t *testing.T) { 166 s := bufio.NewScanner(bytes.NewReader([]byte(`--- 167 stuff: 1 168 169 --- 170 `))) 171 s.Split(splitYAMLDocument) 172 if !s.Scan() { 173 t.Fatalf("should have been able to scan") 174 } 175 t.Logf("scan: %s", s.Text()) 176 if !s.Scan() { 177 t.Fatalf("should have been able to scan") 178 } 179 t.Logf("scan: %s", s.Text()) 180 if s.Scan() { 181 t.Fatalf("scan should have been done") 182 } 183 if s.Err() != nil { 184 t.Fatalf("err should have been nil: %v", s.Err()) 185 } 186 } 187 188 func TestDecodeYAML(t *testing.T) { 189 s := NewYAMLToJSONDecoder(bytes.NewReader([]byte(`--- 190 stuff: 1 191 192 --- 193 `))) 194 obj := generic{} 195 if err := s.Decode(&obj); err != nil { 196 t.Fatalf("unexpected error: %v", err) 197 } 198 if fmt.Sprintf("%#v", obj) != `yaml.generic{"stuff":1}` { 199 t.Errorf("unexpected object: %#v", obj) 200 } 201 obj = generic{} 202 if err := s.Decode(&obj); err != nil { 203 t.Fatalf("unexpected error: %v", err) 204 } 205 if len(obj) != 0 { 206 t.Fatalf("unexpected object: %#v", obj) 207 } 208 obj = generic{} 209 if err := s.Decode(&obj); err != io.EOF { 210 t.Fatalf("unexpected error: %v", err) 211 } 212 } 213 214 func TestDecodeYAMLSeparatorValidation(t *testing.T) { 215 s := NewYAMLToJSONDecoder(bytes.NewReader([]byte(`--- 216 stuff: 1 217 --- # Make sure termination happen with inline comment 218 stuff: 2 219 --- 220 stuff: 3 221 --- Make sure uncommented content results YAMLSyntaxError 222 223 `))) 224 obj := generic{} 225 if err := s.Decode(&obj); err != nil { 226 t.Fatalf("unexpected error: %v", err) 227 } 228 if fmt.Sprintf("%#v", obj) != `yaml.generic{"stuff":1}` { 229 t.Errorf("unexpected object: %#v", obj) 230 } 231 obj = generic{} 232 if err := s.Decode(&obj); err != nil { 233 t.Fatalf("unexpected error: %v", err) 234 } 235 if fmt.Sprintf("%#v", obj) != `yaml.generic{"stuff":2}` { 236 t.Errorf("unexpected object: %#v", obj) 237 } 238 obj = generic{} 239 err := s.Decode(&obj) 240 if err == nil { 241 t.Fatalf("expected YamlSyntaxError, got nil instead") 242 } 243 if _, ok := err.(YAMLSyntaxError); !ok { 244 t.Fatalf("unexpected error: %v", err) 245 } 246 } 247 248 func TestDecodeBrokenYAML(t *testing.T) { 249 s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`--- 250 stuff: 1 251 test-foo: 1 252 253 --- 254 `)), 100) 255 obj := generic{} 256 err := s.Decode(&obj) 257 if err == nil { 258 t.Fatal("expected error with yaml: violate, got no error") 259 } 260 fmt.Printf("err: %s\n", err.Error()) 261 if !strings.Contains(err.Error(), "yaml: line 3:") { 262 t.Fatalf("expected %q to have 'yaml: line 3:' found a tab character", err.Error()) 263 } 264 } 265 266 func TestDecodeBrokenJSON(t *testing.T) { 267 s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`{ 268 "foo": { 269 "stuff": 1 270 "otherStuff": 2 271 } 272 } 273 `)), 100) 274 obj := generic{} 275 err := s.Decode(&obj) 276 if err == nil { 277 t.Fatal("expected error with json: prefix, got no error") 278 } 279 const msg = `json: offset 28: invalid character '"' after object key:value pair` 280 if msg != err.Error() { 281 t.Fatalf("expected %q, got %q", msg, err.Error()) 282 } 283 } 284 285 type generic map[string]interface{} 286 287 func TestYAMLOrJSONDecoder(t *testing.T) { 288 testCases := []struct { 289 input string 290 buffer int 291 isJSON bool 292 err bool 293 out []generic 294 }{ 295 {` {"1":2}{"3":4}`, 2, true, false, []generic{ 296 {"1": 2}, 297 {"3": 4}, 298 }}, 299 {" \n{}", 3, true, false, []generic{ 300 {}, 301 }}, 302 {" \na: b", 2, false, false, []generic{ 303 {"a": "b"}, 304 }}, 305 {" \n{\"a\": \"b\"}", 2, false, true, []generic{ 306 {"a": "b"}, 307 }}, 308 {" \n{\"a\": \"b\"}", 3, true, false, []generic{ 309 {"a": "b"}, 310 }}, 311 {` {"a":"b"}`, 100, true, false, []generic{ 312 {"a": "b"}, 313 }}, 314 {"", 1, false, false, []generic{}}, 315 {"foo: bar\n---\nbaz: biz", 100, false, false, []generic{ 316 {"foo": "bar"}, 317 {"baz": "biz"}, 318 }}, 319 {"---\nfoo: bar\n--- # with Comment\nbaz: biz", 100, false, false, []generic{ 320 {"foo": "bar"}, 321 {"baz": "biz"}, 322 }}, 323 {"foo: bar\n---\n", 100, false, false, []generic{ 324 {"foo": "bar"}, 325 }}, 326 {"foo: bar\n---", 100, false, false, []generic{ 327 {"foo": "bar"}, 328 }}, 329 {"foo: bar\n--", 100, false, true, []generic{ 330 {"foo": "bar"}, 331 }}, 332 {"foo: bar\n-", 100, false, true, []generic{ 333 {"foo": "bar"}, 334 }}, 335 {"foo: bar\n", 100, false, false, []generic{ 336 {"foo": "bar"}, 337 }}, 338 } 339 for i, testCase := range testCases { 340 decoder := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(testCase.input)), testCase.buffer) 341 objs := []generic{} 342 343 var err error 344 for { 345 out := make(generic) 346 err = decoder.Decode(&out) 347 if err != nil { 348 break 349 } 350 objs = append(objs, out) 351 } 352 if err != io.EOF { 353 switch { 354 case testCase.err && err == nil: 355 t.Errorf("%d: unexpected non-error", i) 356 continue 357 case !testCase.err && err != nil: 358 t.Errorf("%d: unexpected error: %v", i, err) 359 continue 360 case err != nil: 361 continue 362 } 363 } 364 switch decoder.decoder.(type) { 365 case *YAMLToJSONDecoder: 366 if testCase.isJSON { 367 t.Errorf("%d: expected JSON decoder, got YAML", i) 368 } 369 case *json.Decoder: 370 if !testCase.isJSON { 371 t.Errorf("%d: expected YAML decoder, got JSON", i) 372 } 373 } 374 if fmt.Sprintf("%#v", testCase.out) != fmt.Sprintf("%#v", objs) { 375 t.Errorf("%d: objects were not equal: \n%#v\n%#v", i, testCase.out, objs) 376 } 377 } 378 } 379 380 func TestReadSingleLongLine(t *testing.T) { 381 testReadLines(t, []int{128 * 1024}) 382 } 383 384 func TestReadRandomLineLengths(t *testing.T) { 385 minLength := 100 386 maxLength := 96 * 1024 387 maxLines := 100 388 389 lineLengths := make([]int, maxLines) 390 for i := 0; i < maxLines; i++ { 391 lineLengths[i] = rand.Intn(maxLength-minLength) + minLength 392 } 393 394 testReadLines(t, lineLengths) 395 } 396 397 func testReadLines(t *testing.T, lineLengths []int) { 398 var ( 399 lines [][]byte 400 inputStream []byte 401 ) 402 for _, lineLength := range lineLengths { 403 inputLine := make([]byte, lineLength+1) 404 for i := 0; i < lineLength; i++ { 405 char := rand.Intn('z'-'A') + 'A' 406 inputLine[i] = byte(char) 407 } 408 inputLine[len(inputLine)-1] = '\n' 409 lines = append(lines, inputLine) 410 } 411 for _, line := range lines { 412 inputStream = append(inputStream, line...) 413 } 414 415 // init Reader 416 reader := bufio.NewReader(bytes.NewReader(inputStream)) 417 lineReader := &LineReader{reader: reader} 418 419 // read lines 420 var readLines [][]byte 421 for range lines { 422 bytes, err := lineReader.Read() 423 if err != nil && err != io.EOF { 424 t.Fatalf("failed to read lines: %v", err) 425 } 426 readLines = append(readLines, bytes) 427 } 428 429 // validate 430 for i := range lines { 431 if len(lines[i]) != len(readLines[i]) { 432 t.Fatalf("expected line length: %d, but got %d", len(lines[i]), len(readLines[i])) 433 } 434 if !reflect.DeepEqual(lines[i], readLines[i]) { 435 t.Fatalf("expected line: %v, but got %v", lines[i], readLines[i]) 436 } 437 } 438 } 439 440 func TestTypedJSONOrYamlErrors(t *testing.T) { 441 s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`{ 442 "foo": { 443 "stuff": 1 444 "otherStuff": 2 445 } 446 } 447 `)), 100) 448 obj := generic{} 449 err := s.Decode(&obj) 450 if err == nil { 451 t.Fatal("expected error with json: prefix, got no error") 452 } 453 if _, ok := err.(JSONSyntaxError); !ok { 454 t.Fatalf("expected %q to be of type JSONSyntaxError", err.Error()) 455 } 456 457 s = NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`--- 458 stuff: 1 459 test-foo: 1 460 461 --- 462 `)), 100) 463 obj = generic{} 464 err = s.Decode(&obj) 465 if err == nil { 466 t.Fatal("expected error with yaml: prefix, got no error") 467 } 468 if _, ok := err.(YAMLSyntaxError); !ok { 469 t.Fatalf("expected %q to be of type YAMLSyntaxError", err.Error()) 470 } 471 } 472 473 func TestUnmarshal(t *testing.T) { 474 mapWithIntegerBytes := []byte(`replicas: 1`) 475 mapWithInteger := make(map[string]interface{}) 476 if err := Unmarshal(mapWithIntegerBytes, &mapWithInteger); err != nil { 477 t.Fatalf("unexpected error unmarshaling yaml: %v", err) 478 } 479 if _, ok := mapWithInteger["replicas"].(int64); !ok { 480 t.Fatalf(`Expected number in map to be int64 but got "%T"`, mapWithInteger["replicas"]) 481 } 482 483 sliceWithIntegerBytes := []byte(`- 1`) 484 var sliceWithInteger []interface{} 485 if err := Unmarshal(sliceWithIntegerBytes, &sliceWithInteger); err != nil { 486 t.Fatalf("unexpected error unmarshaling yaml: %v", err) 487 } 488 if _, ok := sliceWithInteger[0].(int64); !ok { 489 t.Fatalf(`Expected number in slice to be int64 but got "%T"`, sliceWithInteger[0]) 490 } 491 492 integerBytes := []byte(`1`) 493 var integer interface{} 494 if err := Unmarshal(integerBytes, &integer); err != nil { 495 t.Fatalf("unexpected error unmarshaling yaml: %v", err) 496 } 497 if _, ok := integer.(int64); !ok { 498 t.Fatalf(`Expected number to be int64 but got "%T"`, integer) 499 } 500 501 otherTypeBytes := []byte(`123: 2`) 502 otherType := make(map[int]interface{}) 503 if err := Unmarshal(otherTypeBytes, &otherType); err != nil { 504 t.Fatalf("unexpected error unmarshaling yaml: %v", err) 505 } 506 if _, ok := otherType[123].(int64); ok { 507 t.Fatalf(`Expected number not to be converted to int64`) 508 } 509 if _, ok := otherType[123].(float64); !ok { 510 t.Fatalf(`Expected number to be float64 but got "%T"`, otherType[123]) 511 } 512 }