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.

312 lines
6.0 KiB

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