diagnostics_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package metric
  2. import (
  3. "testing"
  4. "time"
  5. )
  6. // MockUpdater implements the Updater interface for testing
  7. type MockUpdater struct {
  8. }
  9. func (m *MockUpdater) Update(updateSet *UpdateSet) {
  10. }
  11. // Test Update func in DiagnosticsModule and check if diagnostics pass
  12. func TestDiagnosticsModule_Update(t *testing.T) {
  13. mockUpdater := &MockUpdater{}
  14. module := NewDiagnosticsModule(mockUpdater)
  15. // Test with valid update set containing node metrics
  16. timestamp := time.Now()
  17. updateSet := &UpdateSet{
  18. Timestamp: timestamp,
  19. Updates: []Update{
  20. {
  21. Name: KubeNodeStatusCapacityCPUCores,
  22. Value: 4.0,
  23. },
  24. {
  25. Name: NodeTotalHourlyCost,
  26. Value: 0.50,
  27. },
  28. },
  29. }
  30. module.Update(updateSet)
  31. // Check both diagnostics
  32. nodeDetails, err := module.DiagnosticsDetails(NodesDiagnosticMetricID)
  33. if err != nil {
  34. t.Error("Expected no error for valid diagnostic ID")
  35. }
  36. if nodeDetails["passed"] != true {
  37. t.Error("Expected node diagnostic to pass")
  38. }
  39. kubecostDetails, err := module.DiagnosticsDetails(KubecostDiagnosticMetricID)
  40. if err != nil {
  41. t.Error("Expected no error for valid diagnostic ID")
  42. }
  43. if kubecostDetails["passed"] != true {
  44. t.Error("Expected kubecost diagnostic to pass")
  45. }
  46. }
  47. // Test Update func in DiagnosticsModule with missing metrics and test if diagnostics fail
  48. func TestDiagnosticsModule_UpdateWithMissingMetrics(t *testing.T) {
  49. mockUpdater := &MockUpdater{}
  50. module := NewDiagnosticsModule(mockUpdater)
  51. timestamp := time.Now()
  52. updateSet := &UpdateSet{
  53. Timestamp: timestamp,
  54. Updates: []Update{
  55. {
  56. Name: "some_other_metric",
  57. Value: 1.0,
  58. },
  59. },
  60. }
  61. module.Update(updateSet)
  62. // Check that diagnostics fail when their metrics are missing
  63. nodeDetails, err := module.DiagnosticsDetails(NodesDiagnosticMetricID)
  64. if err != nil {
  65. t.Error("Expected no error for valid diagnostic ID")
  66. }
  67. if nodeDetails["passed"] != false {
  68. t.Error("Expected node diagnostic to fail when metric is missing")
  69. }
  70. kubecostDetails, err := module.DiagnosticsDetails(KubecostDiagnosticMetricID)
  71. if err != nil {
  72. t.Error("Expected no error for valid diagnostic ID")
  73. }
  74. if kubecostDetails["passed"] != false {
  75. t.Error("Expected kubecost diagnostic to fail when metric is missing")
  76. }
  77. }
  78. // Test DiagnosticsDetails func in DiagnosticsModule with invalid and valid diagnostic IDs
  79. func TestDiagnosticsModule_DiagnosticsDetails(t *testing.T) {
  80. mockUpdater := &MockUpdater{}
  81. module := NewDiagnosticsModule(mockUpdater)
  82. // Test with invalid diagnostic ID
  83. _, err := module.DiagnosticsDetails("invalid_id")
  84. if err.Error() != "diagnostic ID: invalid_id not found" {
  85. t.Error("Expected error for invalid diagnostic ID")
  86. }
  87. // Test with valid diagnostic ID
  88. details, err := module.DiagnosticsDetails(NodesDiagnosticMetricID)
  89. if err != nil {
  90. t.Error("Expected no error for valid diagnostic ID")
  91. }
  92. if details["error"] != nil {
  93. t.Error("Expected no error for valid diagnostic ID")
  94. }
  95. // Check required fields
  96. requiredFields := []string{"query", "label", "result", "passed", "docLink"}
  97. for _, field := range requiredFields {
  98. if details[field] == nil {
  99. t.Errorf("Expected field %s to be present", field)
  100. }
  101. }
  102. }
  103. // Test concurrent access(race condition) to DiagnosticsModule
  104. func TestDiagnosticsModule_ConcurrentAccess(t *testing.T) {
  105. mockUpdater := &MockUpdater{}
  106. module := NewDiagnosticsModule(mockUpdater)
  107. // Test concurrent access to diagnostics
  108. done := make(chan bool, 2)
  109. go func() {
  110. for i := 0; i < 100; i++ {
  111. module.DiagnosticsDefinitions()
  112. }
  113. done <- true
  114. }()
  115. go func() {
  116. for i := 0; i < 100; i++ {
  117. timestamp := time.Now()
  118. updateSet := &UpdateSet{
  119. Timestamp: timestamp,
  120. Updates: []Update{
  121. {
  122. Name: KubeNodeStatusCapacityCPUCores,
  123. Value: float64(i),
  124. },
  125. },
  126. }
  127. module.Update(updateSet)
  128. }
  129. done <- true
  130. }()
  131. <-done
  132. <-done
  133. // If we get here without a race condition, the test passes
  134. }
  135. // Test reset of diagnostics after details are retrieved
  136. func TestDiagnosticsModule_ResetAfterDetails(t *testing.T) {
  137. mockUpdater := &MockUpdater{}
  138. module := NewDiagnosticsModule(mockUpdater)
  139. // Add some data
  140. timestamp := time.Now()
  141. updateSet := &UpdateSet{
  142. Timestamp: timestamp,
  143. Updates: []Update{
  144. {
  145. Name: KubeNodeStatusCapacityCPUCores,
  146. Value: 4.0,
  147. },
  148. },
  149. }
  150. module.Update(updateSet)
  151. // Get details (this should reset the diagnostic)
  152. details, err := module.DiagnosticsDetails(NodesDiagnosticMetricID)
  153. if err != nil {
  154. t.Error("Expected no error for valid diagnostic ID")
  155. }
  156. if details["passed"] != true {
  157. t.Error("Expected diagnostic to pass before reset")
  158. }
  159. // Get details again (should be reset)
  160. details2, err := module.DiagnosticsDetails(NodesDiagnosticMetricID)
  161. if err != nil {
  162. t.Error("Expected no error for valid diagnostic ID")
  163. }
  164. if details2["passed"] != false {
  165. t.Error("Expected diagnostic to be reset after first details call")
  166. }
  167. }