go.temporal.io/server@v1.23.0/common/future/future_test.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package future
    26  
    27  import (
    28  	"context"
    29  	"runtime"
    30  	"sync"
    31  	"testing"
    32  
    33  	"github.com/stretchr/testify/require"
    34  	"github.com/stretchr/testify/suite"
    35  )
    36  
    37  type (
    38  	futureSuite struct {
    39  		*require.Assertions
    40  		suite.Suite
    41  
    42  		future *FutureImpl[int]
    43  		value  int
    44  		err    error
    45  	}
    46  )
    47  
    48  func BenchmarkFutureAvailable(b *testing.B) {
    49  	b.ReportAllocs()
    50  
    51  	ctx := context.Background()
    52  	futures := make([]*FutureImpl[interface{}], b.N)
    53  	for n := 0; n < b.N; n++ {
    54  		futures[n] = NewFuture[interface{}]()
    55  	}
    56  
    57  	b.ResetTimer()
    58  	for n := 0; n < b.N; n++ {
    59  		future := futures[n]
    60  		future.Set(nil, nil)
    61  		_, _ = future.Get(ctx)
    62  	}
    63  }
    64  
    65  func BenchmarkFutureGet(b *testing.B) {
    66  	b.ReportAllocs()
    67  
    68  	future := NewFuture[interface{}]()
    69  	future.Set(nil, nil)
    70  	ctx := context.Background()
    71  	for n := 0; n < b.N; n++ {
    72  		_, _ = future.Get(ctx)
    73  	}
    74  }
    75  
    76  func BenchmarkFutureReady(b *testing.B) {
    77  	b.ReportAllocs()
    78  
    79  	future := NewFuture[interface{}]()
    80  	future.Set(nil, nil)
    81  	for n := 0; n < b.N; n++ {
    82  		_ = future.Ready()
    83  	}
    84  }
    85  
    86  func TestFutureSuite(t *testing.T) {
    87  	s := new(futureSuite)
    88  	suite.Run(t, s)
    89  }
    90  
    91  func (s *futureSuite) SetupSuite() {
    92  	s.Assertions = require.New(s.T())
    93  }
    94  
    95  func (s *futureSuite) TearDownSuite() {
    96  
    97  }
    98  
    99  func (s *futureSuite) SetupTest() {
   100  	s.future = NewFuture[int]()
   101  	s.value = 123
   102  	s.err = nil
   103  }
   104  
   105  func (s *futureSuite) TearDownTest() {
   106  
   107  }
   108  
   109  func (s *futureSuite) TestSetGetReady_Sequential() {
   110  	s.False(s.future.Ready())
   111  	s.future.Set(s.value, s.err)
   112  
   113  	value, err := s.future.Get(context.Background())
   114  	s.True(s.future.Ready())
   115  	s.Equal(s.value, value)
   116  	s.Equal(s.err, err)
   117  }
   118  
   119  func (s *futureSuite) TestSetGetReady_Parallel() {
   120  	numGets := 1024
   121  
   122  	startWG := sync.WaitGroup{}
   123  	endWG := sync.WaitGroup{}
   124  
   125  	startWG.Add(numGets)
   126  	endWG.Add(numGets)
   127  
   128  	s.False(s.future.Ready())
   129  	go func() {
   130  		startWG.Wait()
   131  		s.future.Set(s.value, s.err)
   132  	}()
   133  	for i := 0; i < numGets; i++ {
   134  		go func() {
   135  			defer endWG.Done()
   136  
   137  			ctx := context.Background()
   138  			startWG.Wait()
   139  
   140  			value, err := s.future.Get(ctx)
   141  			s.True(s.future.Ready())
   142  			s.Equal(s.value, value)
   143  			s.Equal(s.err, err)
   144  		}()
   145  		startWG.Done()
   146  	}
   147  
   148  	endWG.Wait()
   149  }
   150  
   151  func (s *futureSuite) TestSetReadyGet_Sequential() {
   152  	s.False(s.future.Ready())
   153  	s.future.Set(s.value, s.err)
   154  
   155  	s.True(s.future.Ready())
   156  	value, err := s.future.Get(context.Background())
   157  	s.Equal(s.value, value)
   158  	s.Equal(s.err, err)
   159  }
   160  
   161  func (s *futureSuite) TestSetReadyGet_Parallel() {
   162  	numGets := 1024
   163  
   164  	startWG := sync.WaitGroup{}
   165  	endWG := sync.WaitGroup{}
   166  
   167  	startWG.Add(numGets)
   168  	endWG.Add(numGets)
   169  
   170  	s.False(s.future.Ready())
   171  	go func() {
   172  		startWG.Wait()
   173  		s.future.Set(s.value, s.err)
   174  	}()
   175  	for i := 0; i < numGets; i++ {
   176  		go func() {
   177  			defer endWG.Done()
   178  
   179  			ctx := context.Background()
   180  			startWG.Wait()
   181  
   182  			for !s.future.Ready() {
   183  				runtime.Gosched()
   184  			}
   185  
   186  			value, err := s.future.Get(ctx)
   187  			s.Equal(s.value, value)
   188  			s.Equal(s.err, err)
   189  		}()
   190  		startWG.Done()
   191  	}
   192  
   193  	endWG.Wait()
   194  }
   195  
   196  func (s *futureSuite) TestGetWhenContextCanceled() {
   197  	s.False(s.future.Ready())
   198  	s.future.Set(s.value, s.err)
   199  
   200  	ctx, cancel := context.WithCancel(context.Background())
   201  	cancel()
   202  
   203  	s.True(s.future.Ready())
   204  	value, err := s.future.Get(ctx)
   205  	s.NoError(err, "When .Ready(), .Get() should return the value even if the context is canceled")
   206  	s.Equal(s.value, value)
   207  }