mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 00:01:40 +01:00 
			
		
		
		
	Remove the need for the caller to hold on to and call an unregister function. Both two callers (one real, one test) already have a context they can use. Use context.AfterFunc instead. There are no observable side effects from scheduling too late if the goroutine doesn't run sync. Updates #17148 Change-Id: Ie697dae0e797494fa8ef27fbafa193bfe5ceb307 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			92 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			92 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| package netmon
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 	"testing/synctest"
 | |
| 
 | |
| 	"tailscale.com/util/eventbus"
 | |
| )
 | |
| 
 | |
| func TestLinkChangeLogLimiter(t *testing.T) { synctest.Test(t, syncTestLinkChangeLogLimiter) }
 | |
| 
 | |
| func syncTestLinkChangeLogLimiter(t *testing.T) {
 | |
| 	bus := eventbus.New()
 | |
| 	defer bus.Close()
 | |
| 	mon, err := New(bus, t.Logf)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer mon.Close()
 | |
| 
 | |
| 	var logBuffer bytes.Buffer
 | |
| 	logf := func(format string, args ...any) {
 | |
| 		t.Logf("captured log: "+format, args...)
 | |
| 
 | |
| 		if format[len(format)-1] != '\n' {
 | |
| 			format += "\n"
 | |
| 		}
 | |
| 		fmt.Fprintf(&logBuffer, format, args...)
 | |
| 	}
 | |
| 
 | |
| 	ctx, cancel := context.WithCancel(t.Context())
 | |
| 	defer cancel()
 | |
| 
 | |
| 	logf = LinkChangeLogLimiter(ctx, logf, mon)
 | |
| 
 | |
| 	// Log once, which should write to our log buffer.
 | |
| 	logf("hello %s", "world")
 | |
| 	if got := logBuffer.String(); got != "hello world\n" {
 | |
| 		t.Errorf("unexpected log buffer contents: %q", got)
 | |
| 	}
 | |
| 
 | |
| 	// Log again, which should not write to our log buffer.
 | |
| 	logf("hello %s", "andrew")
 | |
| 	if got := logBuffer.String(); got != "hello world\n" {
 | |
| 		t.Errorf("unexpected log buffer contents: %q", got)
 | |
| 	}
 | |
| 
 | |
| 	// Log a different message, which should write to our log buffer.
 | |
| 	logf("other message")
 | |
| 	if got := logBuffer.String(); got != "hello world\nother message\n" {
 | |
| 		t.Errorf("unexpected log buffer contents: %q", got)
 | |
| 	}
 | |
| 
 | |
| 	// Synthesize a fake major change event, which should clear the format
 | |
| 	// string cache and allow the next log to write to our log buffer.
 | |
| 	//
 | |
| 	// InjectEvent doesn't work because it's not a major event, so we
 | |
| 	// instead reach into the netmon and grab the callback, and then call
 | |
| 	// it ourselves.
 | |
| 	mon.mu.Lock()
 | |
| 	var cb func(*ChangeDelta)
 | |
| 	for _, c := range mon.cbs {
 | |
| 		cb = c
 | |
| 		break
 | |
| 	}
 | |
| 	mon.mu.Unlock()
 | |
| 
 | |
| 	cb(&ChangeDelta{Major: true})
 | |
| 
 | |
| 	logf("hello %s", "world")
 | |
| 	if got := logBuffer.String(); got != "hello world\nother message\nhello world\n" {
 | |
| 		t.Errorf("unexpected log buffer contents: %q", got)
 | |
| 	}
 | |
| 
 | |
| 	// Canceling the context we passed to LinkChangeLogLimiter should
 | |
| 	// unregister the callback from the netmon.
 | |
| 	cancel()
 | |
| 	synctest.Wait()
 | |
| 
 | |
| 	mon.mu.Lock()
 | |
| 	if len(mon.cbs) != 0 {
 | |
| 		t.Errorf("expected no callbacks, got %v", mon.cbs)
 | |
| 	}
 | |
| 	mon.mu.Unlock()
 | |
| }
 |