hostpool_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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"})
  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. // now try to mark b as success; should fail because already marked
  31. respB.Mark(nil)
  32. assert.Equal(t, p.Get().Host(), "c") // would be b if it were not dead
  33. // now restore a
  34. respA = &standardHostPoolResponse{host: "a", pool: p}
  35. respA.Mark(nil)
  36. assert.Equal(t, p.Get().Host(), "a")
  37. assert.Equal(t, p.Get().Host(), "c")
  38. // ensure that we get *something* back when all hosts fail
  39. for _, host := range []string{"a", "b", "c"} {
  40. response := &standardHostPoolResponse{host: host, pool: p}
  41. response.Mark(dummyErr)
  42. }
  43. resp := p.Get()
  44. assert.NotEqual(t, resp, nil)
  45. }
  46. type mockTimer struct {
  47. t int // the time it will always return
  48. }
  49. func (t *mockTimer) between(start time.Time, end time.Time) time.Duration {
  50. return time.Duration(t.t) * time.Millisecond
  51. }
  52. func TestEpsilonGreedy(t *testing.T) {
  53. log.SetOutput(ioutil.Discard)
  54. defer log.SetOutput(os.Stdout)
  55. rand.Seed(10)
  56. iterations := 12000
  57. p := NewEpsilonGreedy([]string{"a", "b"}, 0, &LinearEpsilonValueCalculator{}).(*epsilonGreedyHostPool)
  58. timings := make(map[string]int64)
  59. timings["a"] = 200
  60. timings["b"] = 300
  61. hitCounts := make(map[string]int)
  62. hitCounts["a"] = 0
  63. hitCounts["b"] = 0
  64. log.Printf("starting first run (a, b)")
  65. for i := 0; i < iterations; i += 1 {
  66. if i != 0 && i%100 == 0 {
  67. p.performEpsilonGreedyDecay()
  68. }
  69. hostR := p.Get()
  70. host := hostR.Host()
  71. hitCounts[host]++
  72. timing := timings[host]
  73. p.timer = &mockTimer{t: int(timing)}
  74. hostR.Mark(nil)
  75. }
  76. for host := range hitCounts {
  77. log.Printf("host %s hit %d times (%0.2f percent)", host, hitCounts[host], (float64(hitCounts[host])/float64(iterations))*100.0)
  78. }
  79. assert.Equal(t, hitCounts["a"] > hitCounts["b"], true)
  80. hitCounts["a"] = 0
  81. hitCounts["b"] = 0
  82. log.Printf("starting second run (b, a)")
  83. timings["a"] = 500
  84. timings["b"] = 100
  85. for i := 0; i < iterations; i += 1 {
  86. if i != 0 && i%100 == 0 {
  87. p.performEpsilonGreedyDecay()
  88. }
  89. hostR := p.Get()
  90. host := hostR.Host()
  91. hitCounts[host]++
  92. timing := timings[host]
  93. p.timer = &mockTimer{t: int(timing)}
  94. hostR.Mark(nil)
  95. }
  96. for host := range hitCounts {
  97. log.Printf("host %s hit %d times (%0.2f percent)", host, hitCounts[host], (float64(hitCounts[host])/float64(iterations))*100.0)
  98. }
  99. assert.Equal(t, hitCounts["b"] > hitCounts["a"], true)
  100. }
  101. func BenchmarkEpsilonGreedy(b *testing.B) {
  102. b.StopTimer()
  103. // Make up some response times
  104. zipfDist := rand.NewZipf(rand.New(rand.NewSource(0)), 1.1, 5, 5000)
  105. timings := make([]uint64, b.N)
  106. for i := 0; i < b.N; i++ {
  107. timings[i] = zipfDist.Uint64()
  108. }
  109. // Make the hostpool with a few hosts
  110. p := NewEpsilonGreedy([]string{"a", "b"}, 0, &LinearEpsilonValueCalculator{}).(*epsilonGreedyHostPool)
  111. b.StartTimer()
  112. for i := 0; i < b.N; i++ {
  113. if i != 0 && i%100 == 0 {
  114. p.performEpsilonGreedyDecay()
  115. }
  116. hostR := p.Get()
  117. p.timer = &mockTimer{t: int(timings[i])}
  118. hostR.Mark(nil)
  119. }
  120. }