e2e_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. // Package tests contains test cases. To run the tests go to tests directory and run:
  4. // RUN_TESTBED=1 go test -v
  5. package tests
  6. import (
  7. "fmt"
  8. "path/filepath"
  9. "testing"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/testbed"
  14. )
  15. func TestIdleMode(t *testing.T) {
  16. options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
  17. dataProvider := testbed.NewPerfTestDataProvider(options)
  18. resultDir, err := filepath.Abs(filepath.Join("results", t.Name()))
  19. require.NoError(t, err)
  20. sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
  21. receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
  22. cfg := createConfigYaml(t, sender, receiver, resultDir, nil, nil)
  23. cp := testbed.NewChildProcessCollector()
  24. cleanup, err := cp.PrepareConfig(cfg)
  25. require.NoError(t, err)
  26. t.Cleanup(cleanup)
  27. tc := testbed.NewTestCase(
  28. t,
  29. dataProvider,
  30. sender,
  31. receiver,
  32. cp,
  33. &testbed.PerfTestValidator{},
  34. performanceResultsSummary,
  35. testbed.WithResourceLimits(testbed.ResourceSpec{ExpectedMaxCPU: 20, ExpectedMaxRAM: 83}),
  36. )
  37. tc.StartAgent()
  38. tc.Sleep(tc.Duration)
  39. tc.Stop()
  40. }
  41. const ballastConfig = `
  42. memory_ballast:
  43. size_mib: %d
  44. `
  45. func TestBallastMemory(t *testing.T) {
  46. tests := []struct {
  47. ballastSize uint32
  48. maxRSS uint32
  49. }{
  50. {100, 80},
  51. {500, 110},
  52. {1000, 120},
  53. }
  54. resultDir, err := filepath.Abs(filepath.Join("results", t.Name()))
  55. require.NoError(t, err)
  56. options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
  57. dataProvider := testbed.NewPerfTestDataProvider(options)
  58. for _, test := range tests {
  59. t.Run(fmt.Sprintf("ballast-size-%d", test.ballastSize), func(t *testing.T) {
  60. sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
  61. receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
  62. ballastCfg := createConfigYaml(
  63. t, sender, receiver, resultDir, nil,
  64. map[string]string{"memory_ballast": fmt.Sprintf(ballastConfig, test.ballastSize)})
  65. cp := testbed.NewChildProcessCollector()
  66. cleanup, err := cp.PrepareConfig(ballastCfg)
  67. require.NoError(t, err)
  68. tc := testbed.NewTestCase(
  69. t,
  70. dataProvider,
  71. sender,
  72. receiver,
  73. cp,
  74. &testbed.PerfTestValidator{},
  75. performanceResultsSummary,
  76. testbed.WithSkipResults(),
  77. testbed.WithResourceLimits(
  78. testbed.ResourceSpec{
  79. ExpectedMaxRAM: test.maxRSS,
  80. ResourceCheckPeriod: time.Second,
  81. MaxConsecutiveFailures: 5,
  82. },
  83. ),
  84. )
  85. tc.StartAgent()
  86. var rss, vms uint32
  87. // It is possible that the process is not ready or the ballast code path
  88. // is not hit immediately so we give the process up to a couple of seconds
  89. // to fire up and setup ballast. 2 seconds is a long time for this case but
  90. // it is short enough to not be annoying if the test fails repeatedly
  91. tc.WaitForN(func() bool {
  92. rss, vms, _ = tc.AgentMemoryInfo()
  93. return vms > test.ballastSize
  94. }, time.Second*5, fmt.Sprintf("VMS must be greater than %d", test.ballastSize))
  95. // https://github.com/open-telemetry/opentelemetry-collector/issues/3233
  96. // given that the maxRSS isn't an absolute maximum and that the actual maximum might be a bit off,
  97. // we give some room here instead of failing when the memory usage isn't that much higher than the max
  98. lenientMax := 1.1 * float32(test.maxRSS)
  99. // https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/6927#issuecomment-1138624098
  100. // During garbage collection, we may observe the ballast in rss.
  101. // If this happens, adjust the baseline expectation for RSS size and validate that additional memory is
  102. // still within the expected limit.
  103. garbageCollectionMax := lenientMax + float32(test.ballastSize)
  104. rssTooHigh := fmt.Sprintf("The RSS memory usage (%d) is >10%% higher than the limit (%d).", rss, test.maxRSS)
  105. if rss > test.ballastSize {
  106. assert.LessOrEqual(t, float32(rss), garbageCollectionMax, rssTooHigh)
  107. } else {
  108. assert.LessOrEqual(t, float32(rss), lenientMax, rssTooHigh)
  109. }
  110. cleanup()
  111. tc.Stop()
  112. })
  113. }
  114. }