resource_metrics_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package collectors
  14. import (
  15. "fmt"
  16. "strings"
  17. "testing"
  18. "time"
  19. "github.com/stretchr/testify/mock"
  20. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  21. "k8s.io/component-base/metrics/testutil"
  22. statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
  23. )
  24. type mockSummaryProvider struct {
  25. mock.Mock
  26. }
  27. func (m *mockSummaryProvider) Get(updateStats bool) (*statsapi.Summary, error) {
  28. args := m.Called(updateStats)
  29. return args.Get(0).(*statsapi.Summary), args.Error(1)
  30. }
  31. func (m *mockSummaryProvider) GetCPUAndMemoryStats() (*statsapi.Summary, error) {
  32. args := m.Called()
  33. return args.Get(0).(*statsapi.Summary), args.Error(1)
  34. }
  35. func TestCollectResourceMetrics(t *testing.T) {
  36. testTime := metav1.NewTime(time.Unix(2, 0)) // a static timestamp: 2000
  37. interestedMetrics := []string{
  38. "scrape_error",
  39. "node_cpu_usage_seconds",
  40. "node_memory_working_set_bytes",
  41. "container_cpu_usage_seconds",
  42. "container_memory_working_set_bytes",
  43. }
  44. tests := []struct {
  45. name string
  46. summary *statsapi.Summary
  47. summaryErr error
  48. expectedMetrics string
  49. }{
  50. {
  51. name: "error getting summary",
  52. summary: nil,
  53. summaryErr: fmt.Errorf("failed to get summary"),
  54. expectedMetrics: `
  55. # HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
  56. # TYPE scrape_error gauge
  57. scrape_error 1
  58. `,
  59. },
  60. {
  61. name: "arbitrary node metrics",
  62. summary: &statsapi.Summary{
  63. Node: statsapi.NodeStats{
  64. CPU: &statsapi.CPUStats{
  65. Time: testTime,
  66. UsageCoreNanoSeconds: uint64Ptr(10000000000),
  67. },
  68. Memory: &statsapi.MemoryStats{
  69. Time: testTime,
  70. WorkingSetBytes: uint64Ptr(1000),
  71. },
  72. },
  73. },
  74. summaryErr: nil,
  75. expectedMetrics: `
  76. # HELP node_cpu_usage_seconds [ALPHA] Cumulative cpu time consumed by the node in core-seconds
  77. # TYPE node_cpu_usage_seconds gauge
  78. node_cpu_usage_seconds 10 2000
  79. # HELP node_memory_working_set_bytes [ALPHA] Current working set of the node in bytes
  80. # TYPE node_memory_working_set_bytes gauge
  81. node_memory_working_set_bytes 1000 2000
  82. # HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
  83. # TYPE scrape_error gauge
  84. scrape_error 0
  85. `,
  86. },
  87. {
  88. name: "arbitrary container metrics for different container, pods and namespaces",
  89. summary: &statsapi.Summary{
  90. Pods: []statsapi.PodStats{
  91. {
  92. PodRef: statsapi.PodReference{
  93. Name: "pod_a",
  94. Namespace: "namespace_a",
  95. },
  96. Containers: []statsapi.ContainerStats{
  97. {
  98. Name: "container_a",
  99. CPU: &statsapi.CPUStats{
  100. Time: testTime,
  101. UsageCoreNanoSeconds: uint64Ptr(10000000000),
  102. },
  103. Memory: &statsapi.MemoryStats{
  104. Time: testTime,
  105. WorkingSetBytes: uint64Ptr(1000),
  106. },
  107. },
  108. {
  109. Name: "container_b",
  110. CPU: &statsapi.CPUStats{
  111. Time: testTime,
  112. UsageCoreNanoSeconds: uint64Ptr(10000000000),
  113. },
  114. Memory: &statsapi.MemoryStats{
  115. Time: testTime,
  116. WorkingSetBytes: uint64Ptr(1000),
  117. },
  118. },
  119. },
  120. },
  121. {
  122. PodRef: statsapi.PodReference{
  123. Name: "pod_b",
  124. Namespace: "namespace_b",
  125. },
  126. Containers: []statsapi.ContainerStats{
  127. {
  128. Name: "container_a",
  129. CPU: &statsapi.CPUStats{
  130. Time: testTime,
  131. UsageCoreNanoSeconds: uint64Ptr(10000000000),
  132. },
  133. Memory: &statsapi.MemoryStats{
  134. Time: testTime,
  135. WorkingSetBytes: uint64Ptr(1000),
  136. },
  137. },
  138. },
  139. },
  140. },
  141. },
  142. summaryErr: nil,
  143. expectedMetrics: `
  144. # HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
  145. # TYPE scrape_error gauge
  146. scrape_error 0
  147. # HELP container_cpu_usage_seconds [ALPHA] Cumulative cpu time consumed by the container in core-seconds
  148. # TYPE container_cpu_usage_seconds gauge
  149. container_cpu_usage_seconds{container="container_a",namespace="namespace_a",pod="pod_a"} 10 2000
  150. container_cpu_usage_seconds{container="container_a",namespace="namespace_b",pod="pod_b"} 10 2000
  151. container_cpu_usage_seconds{container="container_b",namespace="namespace_a",pod="pod_a"} 10 2000
  152. # HELP container_memory_working_set_bytes [ALPHA] Current working set of the container in bytes
  153. # TYPE container_memory_working_set_bytes gauge
  154. container_memory_working_set_bytes{container="container_a",namespace="namespace_a",pod="pod_a"} 1000 2000
  155. container_memory_working_set_bytes{container="container_a",namespace="namespace_b",pod="pod_b"} 1000 2000
  156. container_memory_working_set_bytes{container="container_b",namespace="namespace_a",pod="pod_a"} 1000 2000
  157. `,
  158. },
  159. }
  160. for _, test := range tests {
  161. tc := test
  162. t.Run(tc.name, func(t *testing.T) {
  163. provider := &mockSummaryProvider{}
  164. provider.On("GetCPUAndMemoryStats").Return(tc.summary, tc.summaryErr)
  165. collector := NewResourceMetricsCollector(provider)
  166. if err := testutil.CustomCollectAndCompare(collector, strings.NewReader(tc.expectedMetrics), interestedMetrics...); err != nil {
  167. t.Fatal(err)
  168. }
  169. })
  170. }
  171. }
  172. func uint64Ptr(u uint64) *uint64 {
  173. return &u
  174. }