github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }