github.com/cilium/cilium@v1.16.2/pkg/spanstat/spanstat_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package spanstat
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestSpanStatStart(t *testing.T) {
    16  	span1 := Start()
    17  	span1.EndError(nil)
    18  	require.NotEqual(t, time.Duration(0), span1.Total())
    19  }
    20  
    21  func TestSpanStat(t *testing.T) {
    22  	span1 := SpanStat{}
    23  
    24  	// no spans measured yet
    25  	require.Equal(t, time.Duration(0), span1.Total())
    26  	require.Equal(t, time.Duration(0), span1.SuccessTotal())
    27  	require.Equal(t, time.Duration(0), span1.FailureTotal())
    28  
    29  	// End() without Start()
    30  	span1.End(true)
    31  	require.Equal(t, time.Duration(0), span1.Total())
    32  	require.Equal(t, time.Duration(0), span1.SuccessTotal())
    33  	require.Equal(t, time.Duration(0), span1.FailureTotal())
    34  
    35  	// Start() but no end yet
    36  	span1.Start()
    37  	require.Equal(t, time.Duration(0), span1.Total())
    38  	require.Equal(t, time.Duration(0), span1.SuccessTotal())
    39  	require.Equal(t, time.Duration(0), span1.FailureTotal())
    40  
    41  	// First span measured with End()
    42  	span1.End(true)
    43  	spanTotal1 := span1.Total()
    44  	spanSuccessTotal1 := span1.SuccessTotal()
    45  	spanFailureTotal1 := span1.FailureTotal()
    46  	require.NotEqual(t, time.Duration(0), span1.Total())
    47  	require.NotEqual(t, time.Duration(0), span1.SuccessTotal())
    48  	require.Equal(t, time.Duration(0), span1.FailureTotal())
    49  	require.Equal(t, span1.Total(), span1.SuccessTotal()+span1.FailureTotal())
    50  
    51  	// End() without a prior Start(), no change
    52  	span1.End(true)
    53  	require.Equal(t, spanTotal1, span1.Total())
    54  	require.Equal(t, spanSuccessTotal1, span1.SuccessTotal())
    55  	require.Equal(t, spanFailureTotal1, span1.FailureTotal())
    56  
    57  	span1.Start()
    58  	time.Sleep(time.Millisecond * 100)
    59  	span1.End(false) // ensure second measure is different from first.
    60  	require.NotEqual(t, spanTotal1, span1.Total())
    61  	require.Equal(t, spanSuccessTotal1, span1.SuccessTotal())
    62  	require.NotEqual(t, spanFailureTotal1, span1.FailureTotal())
    63  	require.Equal(t, span1.Total(), span1.SuccessTotal()+span1.FailureTotal())
    64  
    65  	span1.Reset()
    66  	require.Equal(t, time.Duration(0), span1.Total())
    67  	require.Equal(t, time.Duration(0), span1.SuccessTotal())
    68  	require.Equal(t, time.Duration(0), span1.FailureTotal())
    69  }
    70  
    71  func TestSpanStatSeconds(t *testing.T) {
    72  	span1 := Start()
    73  	require.NotEqual(t, float64(0), span1.Seconds())
    74  }
    75  
    76  func TestSpanStatSecondsRaceCondition(t *testing.T) {
    77  	span1 := Start()
    78  	var wg sync.WaitGroup
    79  
    80  	for i := 0; i < 10; i++ {
    81  		wg.Add(1)
    82  		go func(span *SpanStat) {
    83  			defer wg.Done()
    84  			require.NotEqual(t, float64(0), span1.Seconds())
    85  		}(span1)
    86  	}
    87  	wg.Wait()
    88  }
    89  
    90  func TestSpanStatRaceCondition(t *testing.T) {
    91  	type fields struct {
    92  		runFunc func(span *SpanStat) float64
    93  	}
    94  	tests := []struct {
    95  		name   string
    96  		fields fields
    97  	}{
    98  		{
    99  			name: "End function",
   100  			fields: fields{
   101  				runFunc: func(span *SpanStat) float64 {
   102  					return span.End(true).Seconds()
   103  				},
   104  			},
   105  		},
   106  		{
   107  			name: "EndError function",
   108  			fields: fields{
   109  				runFunc: func(span *SpanStat) float64 {
   110  					return span.EndError(fmt.Errorf("dummy error")).Seconds()
   111  				},
   112  			},
   113  		},
   114  		{
   115  			name: "Seconds function",
   116  			fields: fields{
   117  				runFunc: func(span *SpanStat) float64 {
   118  					return span.Seconds()
   119  				},
   120  			},
   121  		},
   122  		{
   123  			name: "Total function",
   124  			fields: fields{
   125  				runFunc: func(span *SpanStat) float64 {
   126  					return span.Total().Seconds() + 1
   127  				},
   128  			},
   129  		},
   130  		{
   131  			name: "FailureTotal function",
   132  			fields: fields{
   133  				runFunc: func(span *SpanStat) float64 {
   134  					return span.FailureTotal().Seconds() + 1
   135  				},
   136  			},
   137  		},
   138  		{
   139  			name: "SuccessTotal function",
   140  			fields: fields{
   141  				runFunc: func(span *SpanStat) float64 {
   142  					return span.SuccessTotal().Seconds() + 1
   143  				},
   144  			},
   145  		},
   146  		{
   147  			name: "Reset function",
   148  			fields: fields{
   149  				runFunc: func(span *SpanStat) float64 {
   150  					span.Reset()
   151  					return 1
   152  				},
   153  			},
   154  		},
   155  	}
   156  
   157  	for _, tt := range tests {
   158  		t.Run(tt.name, func(t *testing.T) {
   159  			span := Start()
   160  			var wg sync.WaitGroup
   161  
   162  			for i := 0; i < 5; i++ {
   163  				wg.Add(1)
   164  				go func(span *SpanStat) {
   165  					defer wg.Done()
   166  					require.NotEqual(t, tt.fields.runFunc(span), float64(0))
   167  				}(span)
   168  			}
   169  			wg.Wait()
   170  		})
   171  	}
   172  }