github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/concurrency_test.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package engine
     5  
     6  import (
     7  	"flag"
     8  	"fmt"
     9  	"math/rand"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/keybase/client/go/libkb"
    14  	"github.com/stretchr/testify/require"
    15  	context "golang.org/x/net/context"
    16  )
    17  
    18  var runConc = flag.Bool("conc", false, "run (expensive) concurrency tests")
    19  
    20  func TestConcurrentLogin(t *testing.T) {
    21  	if !*runConc {
    22  		t.Skip("Skipping ConcurrentLogin test")
    23  	}
    24  	tc := SetupEngineTest(t, "login")
    25  	defer tc.Cleanup()
    26  
    27  	u := CreateAndSignupFakeUser(tc, "login")
    28  
    29  	var lwg sync.WaitGroup
    30  	var mwg sync.WaitGroup
    31  
    32  	done := make(chan bool)
    33  
    34  	for i := 0; i < 10; i++ {
    35  		lwg.Add(1)
    36  		go func(index int) {
    37  			defer lwg.Done()
    38  			for j := 0; j < 4; j++ {
    39  				Logout(tc)
    40  				err := u.Login(tc.G)
    41  				require.NoError(t, err)
    42  			}
    43  			fmt.Printf("logout/login #%d done\n", index)
    44  		}(i)
    45  
    46  		mwg.Add(1)
    47  		go func(index int) {
    48  			defer mwg.Done()
    49  			for {
    50  				select {
    51  				case <-done:
    52  					fmt.Printf("func caller %d done\n", index)
    53  					return
    54  				default:
    55  					_, err := tc.G.ActiveDevice.NIST(context.Background())
    56  					require.NoError(t, err)
    57  					tc.G.ActiveDevice.UID()
    58  					tc.G.ActiveDevice.Valid()
    59  				}
    60  			}
    61  		}(i)
    62  	}
    63  
    64  	lwg.Wait()
    65  	close(done)
    66  	mwg.Wait()
    67  }
    68  
    69  // TestConcurrentGetPassphraseStream tries calling logout, login,
    70  // and GetPassphraseStream to check for race conditions.
    71  // Use the -race flag to test it.
    72  func TestConcurrentGetPassphraseStream(t *testing.T) {
    73  	if !*runConc {
    74  		t.Skip("Skipping ConcurrentGetPassphraseStream test")
    75  	}
    76  	tc := SetupEngineTest(t, "login")
    77  	defer tc.Cleanup()
    78  
    79  	u := CreateAndSignupFakeUser(tc, "login")
    80  
    81  	var lwg sync.WaitGroup
    82  	var mwg sync.WaitGroup
    83  
    84  	done := make(chan bool)
    85  
    86  	for i := 0; i < 10; i++ {
    87  		lwg.Add(1)
    88  		go func(index int) {
    89  			defer lwg.Done()
    90  			for j := 0; j < 4; j++ {
    91  				Logout(tc)
    92  				err := u.Login(tc.G)
    93  				require.NoError(t, err)
    94  			}
    95  			fmt.Printf("logout/login #%d done\n", index)
    96  		}(i)
    97  
    98  		mwg.Add(1)
    99  		go func(index int) {
   100  			defer mwg.Done()
   101  			for {
   102  				select {
   103  				case <-done:
   104  					fmt.Printf("func caller %d done\n", index)
   105  					return
   106  				default:
   107  					tc.G.ActiveDevice.PassphraseStream()
   108  				}
   109  			}
   110  		}(i)
   111  	}
   112  
   113  	lwg.Wait()
   114  	close(done)
   115  	mwg.Wait()
   116  }
   117  
   118  // TestConcurrentLogin tries calling logout, login, and many of
   119  // the exposed methods in ActiveDevice concurrently.  Use the
   120  // -race flag to test it.
   121  func TestConcurrentSignup(t *testing.T) {
   122  	if !*runConc {
   123  		t.Skip("Skipping ConcurrentSignup test")
   124  	}
   125  	tc := SetupEngineTest(t, "login")
   126  	defer tc.Cleanup()
   127  
   128  	u := CreateAndSignupFakeUser(tc, "login")
   129  
   130  	var lwg sync.WaitGroup
   131  	var mwg sync.WaitGroup
   132  
   133  	done := make(chan bool)
   134  
   135  	for i := 0; i < 10; i++ {
   136  		lwg.Add(1)
   137  		go func(index int) {
   138  			defer lwg.Done()
   139  			for j := 0; j < 4; j++ {
   140  				Logout(tc)
   141  				err := u.Login(tc.G)
   142  				require.NoError(t, err)
   143  				Logout(tc)
   144  			}
   145  			fmt.Printf("logout/login #%d done\n", index)
   146  		}(i)
   147  
   148  		mwg.Add(1)
   149  		go func(index int) {
   150  			defer mwg.Done()
   151  			_, err := CreateAndSignupFakeUserSafe(tc.G, "login")
   152  			require.NoError(t, err)
   153  			Logout(tc)
   154  			fmt.Printf("func caller %d done\n", index)
   155  		}(i)
   156  	}
   157  
   158  	lwg.Wait()
   159  	close(done)
   160  	mwg.Wait()
   161  }
   162  
   163  // TestConcurrentGlobals tries to find race conditions in
   164  // everything in GlobalContext.
   165  func TestConcurrentGlobals(t *testing.T) {
   166  	if !*runConc {
   167  		t.Skip("Skipping ConcurrentGlobals")
   168  	}
   169  	tc := SetupEngineTest(t, "login")
   170  	defer tc.Cleanup()
   171  
   172  	fns := []func(*libkb.GlobalContext){
   173  		genv,
   174  	}
   175  	var wg sync.WaitGroup
   176  	for i := 0; i < 10; i++ {
   177  		wg.Add(1)
   178  		go func(index int) {
   179  			for j := 0; j < 10; j++ {
   180  				f := fns[rand.Intn(len(fns))]
   181  				f(tc.G)
   182  			}
   183  			wg.Done()
   184  		}(i)
   185  	}
   186  	wg.Wait()
   187  }
   188  
   189  func genv(g *libkb.GlobalContext) {
   190  	g.Env.GetConfig()
   191  	g.Env.GetConfigWriter()
   192  	g.Env.GetCommandLine()
   193  	cf := libkb.NewJSONConfigFile(g, "")
   194  	g.Env.SetConfig(cf, cf)
   195  }