fifo_test.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. Copyright 2014 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 cache
  14. import (
  15. "fmt"
  16. "reflect"
  17. "testing"
  18. "time"
  19. )
  20. func testFifoObjectKeyFunc(obj interface{}) (string, error) {
  21. return obj.(testFifoObject).name, nil
  22. }
  23. type testFifoObject struct {
  24. name string
  25. val interface{}
  26. }
  27. func mkFifoObj(name string, val interface{}) testFifoObject {
  28. return testFifoObject{name: name, val: val}
  29. }
  30. func TestFIFO_basic(t *testing.T) {
  31. f := NewFIFO(testFifoObjectKeyFunc)
  32. const amount = 500
  33. go func() {
  34. for i := 0; i < amount; i++ {
  35. f.Add(mkFifoObj(string([]rune{'a', rune(i)}), i+1))
  36. }
  37. }()
  38. go func() {
  39. for u := uint64(0); u < amount; u++ {
  40. f.Add(mkFifoObj(string([]rune{'b', rune(u)}), u+1))
  41. }
  42. }()
  43. lastInt := int(0)
  44. lastUint := uint64(0)
  45. for i := 0; i < amount*2; i++ {
  46. switch obj := Pop(f).(testFifoObject).val.(type) {
  47. case int:
  48. if obj <= lastInt {
  49. t.Errorf("got %v (int) out of order, last was %v", obj, lastInt)
  50. }
  51. lastInt = obj
  52. case uint64:
  53. if obj <= lastUint {
  54. t.Errorf("got %v (uint) out of order, last was %v", obj, lastUint)
  55. } else {
  56. lastUint = obj
  57. }
  58. default:
  59. t.Fatalf("unexpected type %#v", obj)
  60. }
  61. }
  62. }
  63. func TestFIFO_requeueOnPop(t *testing.T) {
  64. f := NewFIFO(testFifoObjectKeyFunc)
  65. f.Add(mkFifoObj("foo", 10))
  66. _, err := f.Pop(func(obj interface{}) error {
  67. if obj.(testFifoObject).name != "foo" {
  68. t.Fatalf("unexpected object: %#v", obj)
  69. }
  70. return ErrRequeue{Err: nil}
  71. })
  72. if err != nil {
  73. t.Fatalf("unexpected error: %v", err)
  74. }
  75. if _, ok, err := f.GetByKey("foo"); !ok || err != nil {
  76. t.Fatalf("object should have been requeued: %t %v", ok, err)
  77. }
  78. _, err = f.Pop(func(obj interface{}) error {
  79. if obj.(testFifoObject).name != "foo" {
  80. t.Fatalf("unexpected object: %#v", obj)
  81. }
  82. return ErrRequeue{Err: fmt.Errorf("test error")}
  83. })
  84. if err == nil || err.Error() != "test error" {
  85. t.Fatalf("unexpected error: %v", err)
  86. }
  87. if _, ok, err := f.GetByKey("foo"); !ok || err != nil {
  88. t.Fatalf("object should have been requeued: %t %v", ok, err)
  89. }
  90. _, err = f.Pop(func(obj interface{}) error {
  91. if obj.(testFifoObject).name != "foo" {
  92. t.Fatalf("unexpected object: %#v", obj)
  93. }
  94. return nil
  95. })
  96. if err != nil {
  97. t.Fatalf("unexpected error: %v", err)
  98. }
  99. if _, ok, err := f.GetByKey("foo"); ok || err != nil {
  100. t.Fatalf("object should have been removed: %t %v", ok, err)
  101. }
  102. }
  103. func TestFIFO_addUpdate(t *testing.T) {
  104. f := NewFIFO(testFifoObjectKeyFunc)
  105. f.Add(mkFifoObj("foo", 10))
  106. f.Update(mkFifoObj("foo", 15))
  107. if e, a := []interface{}{mkFifoObj("foo", 15)}, f.List(); !reflect.DeepEqual(e, a) {
  108. t.Errorf("Expected %+v, got %+v", e, a)
  109. }
  110. if e, a := []string{"foo"}, f.ListKeys(); !reflect.DeepEqual(e, a) {
  111. t.Errorf("Expected %+v, got %+v", e, a)
  112. }
  113. got := make(chan testFifoObject, 2)
  114. go func() {
  115. for {
  116. got <- Pop(f).(testFifoObject)
  117. }
  118. }()
  119. first := <-got
  120. if e, a := 15, first.val; e != a {
  121. t.Errorf("Didn't get updated value (%v), got %v", e, a)
  122. }
  123. select {
  124. case unexpected := <-got:
  125. t.Errorf("Got second value %v", unexpected.val)
  126. case <-time.After(50 * time.Millisecond):
  127. }
  128. _, exists, _ := f.Get(mkFifoObj("foo", ""))
  129. if exists {
  130. t.Errorf("item did not get removed")
  131. }
  132. }
  133. func TestFIFO_addReplace(t *testing.T) {
  134. f := NewFIFO(testFifoObjectKeyFunc)
  135. f.Add(mkFifoObj("foo", 10))
  136. f.Replace([]interface{}{mkFifoObj("foo", 15)}, "15")
  137. got := make(chan testFifoObject, 2)
  138. go func() {
  139. for {
  140. got <- Pop(f).(testFifoObject)
  141. }
  142. }()
  143. first := <-got
  144. if e, a := 15, first.val; e != a {
  145. t.Errorf("Didn't get updated value (%v), got %v", e, a)
  146. }
  147. select {
  148. case unexpected := <-got:
  149. t.Errorf("Got second value %v", unexpected.val)
  150. case <-time.After(50 * time.Millisecond):
  151. }
  152. _, exists, _ := f.Get(mkFifoObj("foo", ""))
  153. if exists {
  154. t.Errorf("item did not get removed")
  155. }
  156. }
  157. func TestFIFO_detectLineJumpers(t *testing.T) {
  158. f := NewFIFO(testFifoObjectKeyFunc)
  159. f.Add(mkFifoObj("foo", 10))
  160. f.Add(mkFifoObj("bar", 1))
  161. f.Add(mkFifoObj("foo", 11))
  162. f.Add(mkFifoObj("foo", 13))
  163. f.Add(mkFifoObj("zab", 30))
  164. if e, a := 13, Pop(f).(testFifoObject).val; a != e {
  165. t.Fatalf("expected %d, got %d", e, a)
  166. }
  167. f.Add(mkFifoObj("foo", 14)) // ensure foo doesn't jump back in line
  168. if e, a := 1, Pop(f).(testFifoObject).val; a != e {
  169. t.Fatalf("expected %d, got %d", e, a)
  170. }
  171. if e, a := 30, Pop(f).(testFifoObject).val; a != e {
  172. t.Fatalf("expected %d, got %d", e, a)
  173. }
  174. if e, a := 14, Pop(f).(testFifoObject).val; a != e {
  175. t.Fatalf("expected %d, got %d", e, a)
  176. }
  177. }
  178. func TestFIFO_addIfNotPresent(t *testing.T) {
  179. f := NewFIFO(testFifoObjectKeyFunc)
  180. f.Add(mkFifoObj("a", 1))
  181. f.Add(mkFifoObj("b", 2))
  182. f.AddIfNotPresent(mkFifoObj("b", 3))
  183. f.AddIfNotPresent(mkFifoObj("c", 4))
  184. if e, a := 3, len(f.items); a != e {
  185. t.Fatalf("expected queue length %d, got %d", e, a)
  186. }
  187. expectedValues := []int{1, 2, 4}
  188. for _, expected := range expectedValues {
  189. if actual := Pop(f).(testFifoObject).val; actual != expected {
  190. t.Fatalf("expected value %d, got %d", expected, actual)
  191. }
  192. }
  193. }
  194. func TestFIFO_HasSynced(t *testing.T) {
  195. tests := []struct {
  196. actions []func(f *FIFO)
  197. expectedSynced bool
  198. }{
  199. {
  200. actions: []func(f *FIFO){},
  201. expectedSynced: false,
  202. },
  203. {
  204. actions: []func(f *FIFO){
  205. func(f *FIFO) { f.Add(mkFifoObj("a", 1)) },
  206. },
  207. expectedSynced: true,
  208. },
  209. {
  210. actions: []func(f *FIFO){
  211. func(f *FIFO) { f.Replace([]interface{}{}, "0") },
  212. },
  213. expectedSynced: true,
  214. },
  215. {
  216. actions: []func(f *FIFO){
  217. func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
  218. },
  219. expectedSynced: false,
  220. },
  221. {
  222. actions: []func(f *FIFO){
  223. func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
  224. func(f *FIFO) { Pop(f) },
  225. },
  226. expectedSynced: false,
  227. },
  228. {
  229. actions: []func(f *FIFO){
  230. func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
  231. func(f *FIFO) { Pop(f) },
  232. func(f *FIFO) { Pop(f) },
  233. },
  234. expectedSynced: true,
  235. },
  236. }
  237. for i, test := range tests {
  238. f := NewFIFO(testFifoObjectKeyFunc)
  239. for _, action := range test.actions {
  240. action(f)
  241. }
  242. if e, a := test.expectedSynced, f.HasSynced(); a != e {
  243. t.Errorf("test case %v failed, expected: %v , got %v", i, e, a)
  244. }
  245. }
  246. }