hostpool_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package hostpool
  2. import (
  3. "errors"
  4. "github.com/bmizerany/assert"
  5. "io/ioutil"
  6. "log"
  7. "math/rand"
  8. "os"
  9. "testing"
  10. "time"
  11. )
  12. func TestHostPool(t *testing.T) {
  13. log.SetOutput(ioutil.Discard)
  14. defer log.SetOutput(os.Stdout)
  15. dummyErr := errors.New("Dummy Error")
  16. p := New([]string{"a", "b", "c"}).(*standardHostPool)
  17. assert.Equal(t, p.Get().Host(), "a")
  18. assert.Equal(t, p.Get().Host(), "b")
  19. assert.Equal(t, p.Get().Host(), "c")
  20. respA := p.Get()
  21. assert.Equal(t, respA.Host(), "a")
  22. respA.Mark(dummyErr)
  23. respB := p.Get()
  24. respB.Mark(dummyErr)
  25. respC := p.Get()
  26. assert.Equal(t, respC.Host(), "c")
  27. respC.Mark(nil)
  28. // get again, and verify that it's still c
  29. assert.Equal(t, p.Get().Host(), "c")
  30. assert.Equal(t, p.Get().Host(), "c") // would be b if it were not dead
  31. // now restore a
  32. respA = &standardHostPoolResponse{host: "a", ss: p.Selector.(*standardSelector)}
  33. respA.Mark(nil)
  34. assert.Equal(t, p.Get().Host(), "a")
  35. assert.Equal(t, p.Get().Host(), "c")
  36. // ensure that we get *something* back when all hosts fail
  37. for _, host := range []string{"a", "b", "c"} {
  38. response := &standardHostPoolResponse{host: host, ss: p.Selector.(*standardSelector)}
  39. response.Mark(dummyErr)
  40. }
  41. resp := p.Get()
  42. assert.NotEqual(t, resp, nil)
  43. }
  44. type mockTimer struct {
  45. t int // the time it will always return
  46. }
  47. func (t *mockTimer) between(start time.Time, end time.Time) time.Duration {
  48. return time.Duration(t.t) * time.Millisecond
  49. }
  50. func TestEpsilonGreedy(t *testing.T) {
  51. // log.SetOutput(ioutil.Discard)
  52. // defer log.SetOutput(os.Stdout)
  53. rand.Seed(10)
  54. iterations := 12000
  55. p := NewWithSelector([]string{"a", "b"}, NewEpsilonGreedy(0, &LinearEpsilonValueCalculator{})).(*standardHostPool)
  56. timings := make(map[string]int64)
  57. timings["a"] = 200
  58. timings["b"] = 300
  59. hitCounts := make(map[string]int)
  60. hitCounts["a"] = 0
  61. hitCounts["b"] = 0
  62. log.Printf("starting first run (a, b)")
  63. for i := 0; i < iterations; i += 1 {
  64. if i != 0 && i%100 == 0 {
  65. p.Selector.(*epsilonGreedySelector).performEpsilonGreedyDecay()
  66. }
  67. hostR := p.Get()
  68. host := hostR.Host()
  69. hitCounts[host]++
  70. timing := timings[host]
  71. p.Selector.(*epsilonGreedySelector).timer = &mockTimer{t: int(timing)}
  72. hostR.Mark(nil)
  73. }
  74. for host, _ := range hitCounts {
  75. log.Printf("host %s hit %d times (%0.2f percent)", host, hitCounts[host], (float64(hitCounts[host])/float64(iterations))*100.0)
  76. }
  77. assert.Equal(t, hitCounts["a"] > hitCounts["b"], true)
  78. hitCounts["a"] = 0
  79. hitCounts["b"] = 0
  80. log.Printf("starting second run (b, a)")
  81. timings["a"] = 500
  82. timings["b"] = 100
  83. for i := 0; i < iterations; i += 1 {
  84. if i != 0 && i%100 == 0 {
  85. p.Selector.(*epsilonGreedySelector).performEpsilonGreedyDecay()
  86. }
  87. hostR := p.Get()
  88. host := hostR.Host()
  89. hitCounts[host]++
  90. timing := timings[host]
  91. p.Selector.(*epsilonGreedySelector).timer = &mockTimer{t: int(timing)}
  92. hostR.Mark(nil)
  93. }
  94. for host, _ := range hitCounts {
  95. log.Printf("host %s hit %d times (%0.2f percent)", host, hitCounts[host], (float64(hitCounts[host])/float64(iterations))*100.0)
  96. }
  97. assert.Equal(t, hitCounts["b"] > hitCounts["a"], true)
  98. }
  99. func BenchmarkEpsilonGreedy(b *testing.B) {
  100. b.StopTimer()
  101. // Make up some response times
  102. zipfDist := rand.NewZipf(rand.New(rand.NewSource(0)), 1.1, 5, 5000)
  103. timings := make([]uint64, b.N)
  104. for i := 0; i < b.N; i++ {
  105. timings[i] = zipfDist.Uint64()
  106. }
  107. // Make the hostpool with a few hosts
  108. p := NewWithSelector([]string{"a", "b"}, NewEpsilonGreedy(0, &LinearEpsilonValueCalculator{})).(*standardHostPool)
  109. b.StartTimer()
  110. for i := 0; i < b.N; i++ {
  111. if i != 0 && i%100 == 0 {
  112. p.Selector.(*epsilonGreedySelector).performEpsilonGreedyDecay()
  113. }
  114. hostR := p.Get()
  115. p.Selector.(*epsilonGreedySelector).timer = &mockTimer{t: int(timings[i])}
  116. hostR.Mark(nil)
  117. }
  118. }