cache_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package cache
  4. import (
  5. "errors"
  6. "testing"
  7. "time"
  8. )
  9. var startTime = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
  10. func TestSingleCache(t *testing.T) {
  11. testTime := startTime
  12. timeNow := func() time.Time { return testTime }
  13. c := &Single[string, int]{
  14. timeNow: timeNow,
  15. }
  16. t.Run("NoServeExpired", func(t *testing.T) {
  17. testCacheImpl(t, c, &testTime, false)
  18. })
  19. t.Run("ServeExpired", func(t *testing.T) {
  20. c.Empty()
  21. c.ServeExpired = true
  22. testTime = startTime
  23. testCacheImpl(t, c, &testTime, true)
  24. })
  25. }
  26. func TestLocking(t *testing.T) {
  27. testTime := startTime
  28. timeNow := func() time.Time { return testTime }
  29. c := NewLocking(&Single[string, int]{
  30. timeNow: timeNow,
  31. })
  32. // Just verify that the inner cache's behaviour hasn't changed.
  33. testCacheImpl(t, c, &testTime, false)
  34. }
  35. func testCacheImpl(t *testing.T, c Cache[string, int], testTime *time.Time, serveExpired bool) {
  36. var fillTime time.Time
  37. t.Run("InitialFill", func(t *testing.T) {
  38. fillTime = testTime.Add(time.Hour)
  39. val, err := c.Get("key", func() (int, time.Time, error) {
  40. return 123, fillTime, nil
  41. })
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. if val != 123 {
  46. t.Fatalf("got val=%d; want 123", val)
  47. }
  48. })
  49. // Fetching again won't call our fill function
  50. t.Run("SecondFetch", func(t *testing.T) {
  51. *testTime = fillTime.Add(-1 * time.Second)
  52. called := false
  53. val, err := c.Get("key", func() (int, time.Time, error) {
  54. called = true
  55. return -1, fillTime, nil
  56. })
  57. if called {
  58. t.Fatal("wanted no call to fill function")
  59. }
  60. if err != nil {
  61. t.Fatal(err)
  62. }
  63. if val != 123 {
  64. t.Fatalf("got val=%d; want 123", val)
  65. }
  66. })
  67. // Fetching after the expiry time will re-fill
  68. t.Run("ReFill", func(t *testing.T) {
  69. *testTime = fillTime.Add(1)
  70. fillTime = fillTime.Add(time.Hour)
  71. val, err := c.Get("key", func() (int, time.Time, error) {
  72. return 999, fillTime, nil
  73. })
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. if val != 999 {
  78. t.Fatalf("got val=%d; want 999", val)
  79. }
  80. })
  81. // An error on fetch will serve the expired value.
  82. t.Run("FetchError", func(t *testing.T) {
  83. if !serveExpired {
  84. t.Skipf("not testing ServeExpired")
  85. }
  86. *testTime = fillTime.Add(time.Hour + 1)
  87. val, err := c.Get("key", func() (int, time.Time, error) {
  88. return 0, time.Time{}, errors.New("some error")
  89. })
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. if val != 999 {
  94. t.Fatalf("got val=%d; want 999", val)
  95. }
  96. })
  97. // Fetching a different key re-fills
  98. t.Run("DifferentKey", func(t *testing.T) {
  99. *testTime = fillTime.Add(time.Hour + 1)
  100. var calls int
  101. val, err := c.Get("key1", func() (int, time.Time, error) {
  102. calls++
  103. return 123, fillTime, nil
  104. })
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. if val != 123 {
  109. t.Fatalf("got val=%d; want 123", val)
  110. }
  111. if calls != 1 {
  112. t.Errorf("got %d, want 1 call", calls)
  113. }
  114. val, err = c.Get("key2", func() (int, time.Time, error) {
  115. calls++
  116. return 456, fillTime, nil
  117. })
  118. if err != nil {
  119. t.Fatal(err)
  120. }
  121. if val != 456 {
  122. t.Fatalf("got val=%d; want 456", val)
  123. }
  124. if calls != 2 {
  125. t.Errorf("got %d, want 2 call", calls)
  126. }
  127. })
  128. // Calling Forget with the wrong key does nothing, and with the correct
  129. // key will drop the cache.
  130. t.Run("Forget", func(t *testing.T) {
  131. // Add some time so that previously-cached values don't matter.
  132. fillTime = testTime.Add(2 * time.Hour)
  133. *testTime = fillTime.Add(-1 * time.Second)
  134. const key = "key"
  135. var calls int
  136. val, err := c.Get(key, func() (int, time.Time, error) {
  137. calls++
  138. return 123, fillTime, nil
  139. })
  140. if err != nil {
  141. t.Fatal(err)
  142. }
  143. if val != 123 {
  144. t.Fatalf("got val=%d; want 123", val)
  145. }
  146. if calls != 1 {
  147. t.Errorf("got %d, want 1 call", calls)
  148. }
  149. // Forgetting the wrong key does nothing
  150. c.Forget("other")
  151. val, err = c.Get(key, func() (int, time.Time, error) {
  152. t.Fatal("should not be called")
  153. panic("unreachable")
  154. })
  155. if err != nil {
  156. t.Fatal(err)
  157. }
  158. if val != 123 {
  159. t.Fatalf("got val=%d; want 123", val)
  160. }
  161. // Forgetting the correct key re-fills
  162. c.Forget(key)
  163. val, err = c.Get("key2", func() (int, time.Time, error) {
  164. calls++
  165. return 456, fillTime, nil
  166. })
  167. if err != nil {
  168. t.Fatal(err)
  169. }
  170. if val != 456 {
  171. t.Fatalf("got val=%d; want 456", val)
  172. }
  173. if calls != 2 {
  174. t.Errorf("got %d, want 2 call", calls)
  175. }
  176. })
  177. }