MCPcopy
hub / github.com/micro/go-micro / TestCachePenetrationPrevention

Function TestCachePenetrationPrevention

registry/cache/cache_test.go:228–298  ·  view source on GitHub ↗

TestCachePenetrationPrevention verifies the complete flow: 1. Cache populated 2. Cache expires 3. Registry fails 4. Concurrent requests don't stampede registry due to rate limiting 5. Stale cache is returned without hitting registry

(t *testing.T)

Source from the content-addressed store, hash-verified

226// 4. Concurrent requests don't stampede registry due to rate limiting
227// 5. Stale cache is returned without hitting registry
228func TestCachePenetrationPrevention(t *testing.T) {
229 mock := &mockRegistry{
230 services: []*registry.Service{
231 {
232 Name: "test.service",
233 Version: "1.0.0",
234 Nodes: []*registry.Node{
235 {Id: "node1", Address: "localhost:9090"},
236 },
237 },
238 },
239 }
240
241 // Type assertion to *cache is necessary to access internal state for verification
242 c := New(mock, func(o *Options) {
243 o.TTL = 100 * time.Millisecond
244 o.Logger = logger.DefaultLogger
245 // Use short retry interval to test rate limiting
246 o.MinimumRetryInterval = 5 * time.Second
247 }).(*cache)
248
249 // Initial request to populate cache
250 _, err := c.GetService("test.service")
251 if err != nil {
252 t.Fatalf("Initial request failed: %v", err)
253 }
254
255 initialCalls := mock.getCallCount()
256 if initialCalls != 1 {
257 t.Fatalf("Expected 1 initial call, got %d", initialCalls)
258 }
259
260 // Wait for cache to expire (but not past retry interval)
261 time.Sleep(150 * time.Millisecond)
262
263 // Configure mock to fail with delay
264 mock.err = errors.New("etcd overloaded")
265 mock.delay = 100 * time.Millisecond
266
267 // Launch many concurrent requests (simulating stampede)
268 const concurrency = 50
269 var wg sync.WaitGroup
270 wg.Add(concurrency)
271
272 successCount := int32(0)
273
274 for i := 0; i < concurrency; i++ {
275 go func() {
276 defer wg.Done()
277 services, err := c.GetService("test.service")
278 // Should return stale cache without error (rate limiting prevents registry call)
279 if err == nil && len(services) > 0 {
280 atomic.AddInt32(&successCount, 1)
281 }
282 }()
283 }
284
285 wg.Wait()

Callers

nothing calls this directly

Calls 9

getCallCountMethod · 0.95
DoneMethod · 0.80
NewFunction · 0.70
GetServiceMethod · 0.65
AddMethod · 0.65
FatalfMethod · 0.45
SleepMethod · 0.45
WaitMethod · 0.45
ErrorfMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…