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  }