You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
5.7 KiB

  1. package clist
  2. import (
  3. "fmt"
  4. "runtime"
  5. "sync/atomic"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. cmn "github.com/tendermint/tendermint/libs/common"
  10. )
  11. func TestPanicOnMaxLength(t *testing.T) {
  12. maxLength := 1000
  13. l := newWithMax(maxLength)
  14. for i := 0; i < maxLength; i++ {
  15. l.PushBack(1)
  16. }
  17. assert.Panics(t, func() {
  18. l.PushBack(1)
  19. })
  20. }
  21. func TestSmall(t *testing.T) {
  22. l := New()
  23. el1 := l.PushBack(1)
  24. el2 := l.PushBack(2)
  25. el3 := l.PushBack(3)
  26. if l.Len() != 3 {
  27. t.Error("Expected len 3, got ", l.Len())
  28. }
  29. //fmt.Printf("%p %v\n", el1, el1)
  30. //fmt.Printf("%p %v\n", el2, el2)
  31. //fmt.Printf("%p %v\n", el3, el3)
  32. r1 := l.Remove(el1)
  33. //fmt.Printf("%p %v\n", el1, el1)
  34. //fmt.Printf("%p %v\n", el2, el2)
  35. //fmt.Printf("%p %v\n", el3, el3)
  36. r2 := l.Remove(el2)
  37. //fmt.Printf("%p %v\n", el1, el1)
  38. //fmt.Printf("%p %v\n", el2, el2)
  39. //fmt.Printf("%p %v\n", el3, el3)
  40. r3 := l.Remove(el3)
  41. if r1 != 1 {
  42. t.Error("Expected 1, got ", r1)
  43. }
  44. if r2 != 2 {
  45. t.Error("Expected 2, got ", r2)
  46. }
  47. if r3 != 3 {
  48. t.Error("Expected 3, got ", r3)
  49. }
  50. if l.Len() != 0 {
  51. t.Error("Expected len 0, got ", l.Len())
  52. }
  53. }
  54. /*
  55. This test is quite hacky because it relies on SetFinalizer
  56. which isn't guaranteed to run at all.
  57. */
  58. // nolint: megacheck
  59. func _TestGCFifo(t *testing.T) {
  60. const numElements = 1000000
  61. l := New()
  62. gcCount := new(uint64)
  63. // SetFinalizer doesn't work well with circular structures,
  64. // so we construct a trivial non-circular structure to
  65. // track.
  66. type value struct {
  67. Int int
  68. }
  69. done := make(chan struct{})
  70. for i := 0; i < numElements; i++ {
  71. v := new(value)
  72. v.Int = i
  73. l.PushBack(v)
  74. runtime.SetFinalizer(v, func(v *value) {
  75. atomic.AddUint64(gcCount, 1)
  76. })
  77. }
  78. for el := l.Front(); el != nil; {
  79. l.Remove(el)
  80. //oldEl := el
  81. el = el.Next()
  82. //oldEl.DetachPrev()
  83. //oldEl.DetachNext()
  84. }
  85. runtime.GC()
  86. time.Sleep(time.Second * 3)
  87. runtime.GC()
  88. time.Sleep(time.Second * 3)
  89. _ = done
  90. if *gcCount != numElements {
  91. t.Errorf("Expected gcCount to be %v, got %v", numElements,
  92. *gcCount)
  93. }
  94. }
  95. /*
  96. This test is quite hacky because it relies on SetFinalizer
  97. which isn't guaranteed to run at all.
  98. */
  99. // nolint: megacheck
  100. func _TestGCRandom(t *testing.T) {
  101. const numElements = 1000000
  102. l := New()
  103. gcCount := 0
  104. // SetFinalizer doesn't work well with circular structures,
  105. // so we construct a trivial non-circular structure to
  106. // track.
  107. type value struct {
  108. Int int
  109. }
  110. for i := 0; i < numElements; i++ {
  111. v := new(value)
  112. v.Int = i
  113. l.PushBack(v)
  114. runtime.SetFinalizer(v, func(v *value) {
  115. gcCount++
  116. })
  117. }
  118. els := make([]*CElement, 0, numElements)
  119. for el := l.Front(); el != nil; el = el.Next() {
  120. els = append(els, el)
  121. }
  122. for _, i := range cmn.RandPerm(numElements) {
  123. el := els[i]
  124. l.Remove(el)
  125. _ = el.Next()
  126. }
  127. runtime.GC()
  128. time.Sleep(time.Second * 3)
  129. if gcCount != numElements {
  130. t.Errorf("Expected gcCount to be %v, got %v", numElements,
  131. gcCount)
  132. }
  133. }
  134. func TestScanRightDeleteRandom(t *testing.T) {
  135. const numElements = 1000
  136. const numTimes = 100
  137. const numScanners = 10
  138. l := New()
  139. stop := make(chan struct{})
  140. els := make([]*CElement, numElements)
  141. for i := 0; i < numElements; i++ {
  142. el := l.PushBack(i)
  143. els[i] = el
  144. }
  145. // Launch scanner routines that will rapidly iterate over elements.
  146. for i := 0; i < numScanners; i++ {
  147. go func(scannerID int) {
  148. var el *CElement
  149. restartCounter := 0
  150. counter := 0
  151. FOR_LOOP:
  152. for {
  153. select {
  154. case <-stop:
  155. fmt.Println("stopped")
  156. break FOR_LOOP
  157. default:
  158. }
  159. if el == nil {
  160. el = l.FrontWait()
  161. restartCounter++
  162. }
  163. el = el.Next()
  164. counter++
  165. }
  166. fmt.Printf("Scanner %v restartCounter: %v counter: %v\n", scannerID, restartCounter, counter)
  167. }(i)
  168. }
  169. // Remove an element, push back an element.
  170. for i := 0; i < numTimes; i++ {
  171. // Pick an element to remove
  172. rmElIdx := cmn.RandIntn(len(els))
  173. rmEl := els[rmElIdx]
  174. // Remove it
  175. l.Remove(rmEl)
  176. //fmt.Print(".")
  177. // Insert a new element
  178. newEl := l.PushBack(-1*i - 1)
  179. els[rmElIdx] = newEl
  180. if i%100000 == 0 {
  181. fmt.Printf("Pushed %vK elements so far...\n", i/1000)
  182. }
  183. }
  184. // Stop scanners
  185. close(stop)
  186. // time.Sleep(time.Second * 1)
  187. // And remove all the elements.
  188. for el := l.Front(); el != nil; el = el.Next() {
  189. l.Remove(el)
  190. }
  191. if l.Len() != 0 {
  192. t.Fatal("Failed to remove all elements from CList")
  193. }
  194. }
  195. func TestWaitChan(t *testing.T) {
  196. l := New()
  197. ch := l.WaitChan()
  198. // 1) add one element to an empty list
  199. go l.PushBack(1)
  200. <-ch
  201. // 2) and remove it
  202. el := l.Front()
  203. v := l.Remove(el)
  204. if v != 1 {
  205. t.Fatal("where is 1 coming from?")
  206. }
  207. // 3) test iterating forward and waiting for Next (NextWaitChan and Next)
  208. el = l.PushBack(0)
  209. done := make(chan struct{})
  210. pushed := 0
  211. go func() {
  212. for i := 1; i < 100; i++ {
  213. l.PushBack(i)
  214. pushed++
  215. time.Sleep(time.Duration(cmn.RandIntn(25)) * time.Millisecond)
  216. }
  217. close(done)
  218. }()
  219. next := el
  220. seen := 0
  221. FOR_LOOP:
  222. for {
  223. select {
  224. case <-next.NextWaitChan():
  225. next = next.Next()
  226. seen++
  227. if next == nil {
  228. continue
  229. }
  230. case <-done:
  231. break FOR_LOOP
  232. case <-time.After(10 * time.Second):
  233. t.Fatal("max execution time")
  234. }
  235. }
  236. if pushed != seen {
  237. t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
  238. }
  239. // 4) test iterating backwards (PrevWaitChan and Prev)
  240. prev := next
  241. seen = 0
  242. FOR_LOOP2:
  243. for {
  244. select {
  245. case <-prev.PrevWaitChan():
  246. prev = prev.Prev()
  247. seen++
  248. if prev == nil {
  249. t.Fatal("expected PrevWaitChan to block forever on nil when reached first elem")
  250. }
  251. case <-time.After(3 * time.Second):
  252. break FOR_LOOP2
  253. }
  254. }
  255. if pushed != seen {
  256. t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
  257. }
  258. }