healthcheck_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. Copyright 2016 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 healthcheck
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. "math/rand"
  18. "net/http"
  19. "testing"
  20. "time"
  21. "k8s.io/kubernetes/pkg/types"
  22. "k8s.io/kubernetes/pkg/util/sets"
  23. )
  24. type TestCaseData struct {
  25. nodePorts int
  26. numEndpoints int
  27. nodePortList []int
  28. svcNames []types.NamespacedName
  29. }
  30. const (
  31. startPort = 20000
  32. endPort = 40000
  33. )
  34. var (
  35. choices = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
  36. )
  37. func generateRandomString(n int) string {
  38. b := make([]byte, n)
  39. l := len(choices)
  40. for i := range b {
  41. b[i] = choices[rand.Intn(l)]
  42. }
  43. return string(b)
  44. }
  45. func chooseServiceName(tc int, hint int) types.NamespacedName {
  46. var svc types.NamespacedName
  47. svc.Namespace = fmt.Sprintf("ns_%d", tc)
  48. svc.Name = fmt.Sprintf("name_%d", hint)
  49. return svc
  50. }
  51. func generateEndpointSet(max int) sets.String {
  52. s := sets.NewString()
  53. for i := 0; i < max; i++ {
  54. s.Insert(fmt.Sprintf("%d%s", i, generateRandomString(8)))
  55. }
  56. return s
  57. }
  58. func verifyHealthChecks(tc *TestCaseData, t *testing.T) bool {
  59. var success = true
  60. time.Sleep(100 * time.Millisecond)
  61. for i := 0; i < tc.nodePorts; i++ {
  62. t.Logf("Validating HealthCheck works for svc %s nodePort %d\n", tc.svcNames[i], tc.nodePortList[i])
  63. res, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/", tc.nodePortList[i]))
  64. if err != nil {
  65. t.Logf("ERROR: Failed to connect to listening port")
  66. success = false
  67. continue
  68. }
  69. robots, err := ioutil.ReadAll(res.Body)
  70. if res.StatusCode == http.StatusServiceUnavailable {
  71. t.Logf("ERROR: HealthCheck returned %s: %s", res.Status, string(robots))
  72. success = false
  73. continue
  74. }
  75. res.Body.Close()
  76. if err != nil {
  77. t.Logf("Error: reading body of response (%s)", err)
  78. success = false
  79. continue
  80. }
  81. }
  82. if success {
  83. t.Logf("Success: All nodePorts found active")
  84. }
  85. return success
  86. }
  87. func TestHealthChecker(t *testing.T) {
  88. testcases := []TestCaseData{
  89. {
  90. nodePorts: 1,
  91. numEndpoints: 2,
  92. },
  93. {
  94. nodePorts: 10,
  95. numEndpoints: 6,
  96. },
  97. {
  98. nodePorts: 100,
  99. numEndpoints: 1,
  100. },
  101. }
  102. Run()
  103. ports := startPort
  104. for n, tc := range testcases {
  105. tc.nodePortList = make([]int, tc.nodePorts)
  106. tc.svcNames = make([]types.NamespacedName, tc.nodePorts)
  107. for i := 0; i < tc.nodePorts; i++ {
  108. tc.svcNames[i] = chooseServiceName(n, i)
  109. t.Logf("Updating endpoints map for %s %d", tc.svcNames[i], tc.numEndpoints)
  110. for {
  111. UpdateEndpoints(tc.svcNames[i], generateEndpointSet(tc.numEndpoints))
  112. tc.nodePortList[i] = ports
  113. ports++
  114. if AddServiceListener(tc.svcNames[i], tc.nodePortList[i]) {
  115. break
  116. }
  117. DeleteServiceListener(tc.svcNames[i], tc.nodePortList[i])
  118. // Keep searching for a port that works
  119. t.Logf("Failed to bind/listen on port %d...trying next port", ports-1)
  120. if ports > endPort {
  121. t.Errorf("Exhausted range of ports available for tests")
  122. return
  123. }
  124. }
  125. }
  126. t.Logf("Validating if all nodePorts for tc %d work", n)
  127. if !verifyHealthChecks(&tc, t) {
  128. t.Errorf("Healthcheck validation failed")
  129. }
  130. for i := 0; i < tc.nodePorts; i++ {
  131. DeleteServiceListener(tc.svcNames[i], tc.nodePortList[i])
  132. UpdateEndpoints(tc.svcNames[i], sets.NewString())
  133. }
  134. // Ensure that all listeners have been shutdown
  135. if verifyHealthChecks(&tc, t) {
  136. t.Errorf("Healthcheck validation failed")
  137. }
  138. }
  139. }