limit_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package yaml_test
  2. import (
  3. "strings"
  4. "testing"
  5. . "gopkg.in/check.v1"
  6. "gopkg.in/yaml.v2"
  7. )
  8. var limitTests = []struct {
  9. name string
  10. data []byte
  11. error string
  12. }{
  13. {
  14. name: "1000kb of maps with 100 aliases",
  15. data: []byte(`{a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-100) + `], b: &b [*a` + strings.Repeat(`,*a`, 99) + `]}`),
  16. error: "yaml: document contains excessive aliasing",
  17. }, {
  18. name: "1000kb of deeply nested slices",
  19. data: []byte(strings.Repeat(`[`, 1000*1024)),
  20. error: "yaml: exceeded max depth of 10000",
  21. }, {
  22. name: "1000kb of deeply nested maps",
  23. data: []byte("x: " + strings.Repeat(`{`, 1000*1024)),
  24. error: "yaml: exceeded max depth of 10000",
  25. }, {
  26. name: "1000kb of deeply nested indents",
  27. data: []byte(strings.Repeat(`- `, 1000*1024)),
  28. error: "yaml: exceeded max depth of 10000",
  29. }, {
  30. name: "1000kb of 1000-indent lines",
  31. data: []byte(strings.Repeat(strings.Repeat(`- `, 1000)+"\n", 1024/2)),
  32. },
  33. {name: "1kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1*1024/4-1) + `]`)},
  34. {name: "10kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 10*1024/4-1) + `]`)},
  35. {name: "100kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 100*1024/4-1) + `]`)},
  36. {name: "1000kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-1) + `]`)},
  37. {name: "1000kb slice nested at max-depth", data: []byte(strings.Repeat(`[`, 10000) + `1` + strings.Repeat(`,1`, 1000*1024/2-20000-1) + strings.Repeat(`]`, 10000))},
  38. {name: "1000kb slice nested in maps at max-depth", data: []byte("{a,b:\n" + strings.Repeat(" {a,b:", 10000-2) + ` [1` + strings.Repeat(",1", 1000*1024/2-6*10000-1) + `]` + strings.Repeat(`}`, 10000-1))},
  39. {name: "1000kb of 10000-nested lines", data: []byte(strings.Repeat(`- `+strings.Repeat(`[`, 10000)+strings.Repeat(`]`, 10000)+"\n", 1000*1024/20000))},
  40. }
  41. func (s *S) TestLimits(c *C) {
  42. if testing.Short() {
  43. return
  44. }
  45. for _, tc := range limitTests {
  46. var v interface{}
  47. err := yaml.Unmarshal(tc.data, &v)
  48. if len(tc.error) > 0 {
  49. c.Assert(err, ErrorMatches, tc.error, Commentf("testcase: %s", tc.name))
  50. } else {
  51. c.Assert(err, IsNil, Commentf("testcase: %s", tc.name))
  52. }
  53. }
  54. }
  55. func Benchmark1000KB100Aliases(b *testing.B) {
  56. benchmark(b, "1000kb of maps with 100 aliases")
  57. }
  58. func Benchmark1000KBDeeplyNestedSlices(b *testing.B) {
  59. benchmark(b, "1000kb of deeply nested slices")
  60. }
  61. func Benchmark1000KBDeeplyNestedMaps(b *testing.B) {
  62. benchmark(b, "1000kb of deeply nested maps")
  63. }
  64. func Benchmark1000KBDeeplyNestedIndents(b *testing.B) {
  65. benchmark(b, "1000kb of deeply nested indents")
  66. }
  67. func Benchmark1000KB1000IndentLines(b *testing.B) {
  68. benchmark(b, "1000kb of 1000-indent lines")
  69. }
  70. func Benchmark1KBMaps(b *testing.B) {
  71. benchmark(b, "1kb of maps")
  72. }
  73. func Benchmark10KBMaps(b *testing.B) {
  74. benchmark(b, "10kb of maps")
  75. }
  76. func Benchmark100KBMaps(b *testing.B) {
  77. benchmark(b, "100kb of maps")
  78. }
  79. func Benchmark1000KBMaps(b *testing.B) {
  80. benchmark(b, "1000kb of maps")
  81. }
  82. func BenchmarkDeepSlice(b *testing.B) {
  83. benchmark(b, "1000kb slice nested at max-depth")
  84. }
  85. func BenchmarkDeepFlow(b *testing.B) {
  86. benchmark(b, "1000kb slice nested in maps at max-depth")
  87. }
  88. func Benchmark1000KBMaxDepthNested(b *testing.B) {
  89. benchmark(b, "1000kb of 10000-nested lines")
  90. }
  91. func benchmark(b *testing.B, name string) {
  92. for _, t := range limitTests {
  93. if t.name != name {
  94. continue
  95. }
  96. b.ResetTimer()
  97. for i := 0; i < b.N; i++ {
  98. var v interface{}
  99. err := yaml.Unmarshal(t.data, &v)
  100. if len(t.error) > 0 {
  101. if err == nil {
  102. b.Errorf("expected error, got none")
  103. } else if err.Error() != t.error {
  104. b.Errorf("expected error '%s', got '%s'", t.error, err.Error())
  105. }
  106. } else {
  107. if err != nil {
  108. b.Errorf("unexpected error: %v", err)
  109. }
  110. }
  111. }
  112. return
  113. }
  114. b.Errorf("testcase %q not found", name)
  115. }