github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/memberlist/suspicion_test.go (about)

     1  package memberlist
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  )
     7  
     8  func TestSuspicion_remainingSuspicionTime(t *testing.T) {
     9  	cases := []struct {
    10  		n        int32
    11  		k        int32
    12  		elapsed  time.Duration
    13  		min      time.Duration
    14  		max      time.Duration
    15  		expected time.Duration
    16  	}{
    17  		{0, 3, 0, 2 * time.Second, 30 * time.Second, 30 * time.Second},
    18  		{1, 3, 2 * time.Second, 2 * time.Second, 30 * time.Second, 14 * time.Second},
    19  		{2, 3, 3 * time.Second, 2 * time.Second, 30 * time.Second, 4810 * time.Millisecond},
    20  		{3, 3, 4 * time.Second, 2 * time.Second, 30 * time.Second, -2 * time.Second},
    21  		{4, 3, 5 * time.Second, 2 * time.Second, 30 * time.Second, -3 * time.Second},
    22  		{5, 3, 10 * time.Second, 2 * time.Second, 30 * time.Second, -8 * time.Second},
    23  	}
    24  	for i, c := range cases {
    25  		remaining := remainingSuspicionTime(c.n, c.k, c.elapsed, c.min, c.max)
    26  		if remaining != c.expected {
    27  			t.Errorf("case %d: remaining %9.6f != expected %9.6f", i, remaining.Seconds(), c.expected.Seconds())
    28  		}
    29  	}
    30  }
    31  
    32  func TestSuspicion_Timer(t *testing.T) {
    33  	const k = 3
    34  	const min = 500 * time.Millisecond
    35  	const max = 2 * time.Second
    36  
    37  	type pair struct {
    38  		from    string
    39  		newInfo bool
    40  	}
    41  	cases := []struct {
    42  		numConfirmations int
    43  		from             string
    44  		confirmations    []pair
    45  		expected         time.Duration
    46  	}{
    47  		{
    48  			0,
    49  			"me",
    50  			[]pair{},
    51  			max,
    52  		},
    53  		{
    54  			1,
    55  			"me",
    56  			[]pair{
    57  				pair{"me", false},
    58  				pair{"foo", true},
    59  			},
    60  			1250 * time.Millisecond,
    61  		},
    62  		{
    63  			1,
    64  			"me",
    65  			[]pair{
    66  				pair{"me", false},
    67  				pair{"foo", true},
    68  				pair{"foo", false},
    69  				pair{"foo", false},
    70  			},
    71  			1250 * time.Millisecond,
    72  		},
    73  		{
    74  			2,
    75  			"me",
    76  			[]pair{
    77  				pair{"me", false},
    78  				pair{"foo", true},
    79  				pair{"bar", true},
    80  			},
    81  			810 * time.Millisecond,
    82  		},
    83  		{
    84  			3,
    85  			"me",
    86  			[]pair{
    87  				pair{"me", false},
    88  				pair{"foo", true},
    89  				pair{"bar", true},
    90  				pair{"baz", true},
    91  			},
    92  			min,
    93  		},
    94  		{
    95  			3,
    96  			"me",
    97  			[]pair{
    98  				pair{"me", false},
    99  				pair{"foo", true},
   100  				pair{"bar", true},
   101  				pair{"baz", true},
   102  				pair{"zoo", false},
   103  			},
   104  			min,
   105  		},
   106  	}
   107  	for i, c := range cases {
   108  		ch := make(chan time.Duration, 1)
   109  		start := time.Now()
   110  		f := func(numConfirmations int) {
   111  			if numConfirmations != c.numConfirmations {
   112  				t.Errorf("case %d: bad %d != %d", i, numConfirmations, c.numConfirmations)
   113  			}
   114  
   115  			ch <- time.Now().Sub(start)
   116  		}
   117  
   118  		// Create the timer and add the requested confirmations. Wait
   119  		// the fudge amount to help make sure we calculate the timeout
   120  		// overall, and don't accumulate extra time.
   121  		s := newSuspicion(c.from, k, min, max, f)
   122  		fudge := 25 * time.Millisecond
   123  		for _, p := range c.confirmations {
   124  			time.Sleep(fudge)
   125  			if s.Confirm(p.from) != p.newInfo {
   126  				t.Fatalf("case %d: newInfo mismatch for %s", i, p.from)
   127  			}
   128  		}
   129  
   130  		// Wait until right before the timeout and make sure the
   131  		// timer hasn't fired.
   132  		already := time.Duration(len(c.confirmations)) * fudge
   133  		time.Sleep(c.expected - already - fudge)
   134  		select {
   135  		case d := <-ch:
   136  			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
   137  		default:
   138  		}
   139  
   140  		// Wait through the timeout and a little after and make sure it
   141  		// fires.
   142  		time.Sleep(2 * fudge)
   143  		select {
   144  		case <-ch:
   145  		default:
   146  			t.Fatalf("case %d: should have fired", i)
   147  		}
   148  
   149  		// Confirm after to make sure it handles a negative remaining
   150  		// time correctly and doesn't fire again.
   151  		s.Confirm("late")
   152  		time.Sleep(c.expected + 2*fudge)
   153  		select {
   154  		case d := <-ch:
   155  			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
   156  		default:
   157  		}
   158  	}
   159  }
   160  
   161  func TestSuspicion_Timer_ZeroK(t *testing.T) {
   162  	ch := make(chan struct{}, 1)
   163  	f := func(int) {
   164  		ch <- struct{}{}
   165  	}
   166  
   167  	// This should select the min time since there are no expected
   168  	// confirmations to accelerate the timer.
   169  	s := newSuspicion("me", 0, 25*time.Millisecond, 30*time.Second, f)
   170  	if s.Confirm("foo") {
   171  		t.Fatalf("should not provide new information")
   172  	}
   173  
   174  	select {
   175  	case <-ch:
   176  	case <-time.After(50 * time.Millisecond):
   177  		t.Fatalf("should have fired")
   178  	}
   179  }
   180  
   181  func TestSuspicion_Timer_Immediate(t *testing.T) {
   182  	ch := make(chan struct{}, 1)
   183  	f := func(int) {
   184  		ch <- struct{}{}
   185  	}
   186  
   187  	// This should underflow the timeout and fire immediately.
   188  	s := newSuspicion("me", 1, 100*time.Millisecond, 30*time.Second, f)
   189  	time.Sleep(200 * time.Millisecond)
   190  	s.Confirm("foo")
   191  
   192  	// Wait a little while since the function gets called in a goroutine.
   193  	select {
   194  	case <-ch:
   195  	case <-time.After(25 * time.Millisecond):
   196  		t.Fatalf("should have fired")
   197  	}
   198  }