@@ -24,16 +24,15 @@ import (
2424 "testing"
2525 "time"
2626
27- topoutils "vitess.io/vitess/go/test/endtoend/topotest/utils"
28- "vitess.io/vitess/go/vt/log"
29- "vitess.io/vitess/go/vt/topo"
30-
3127 "github.com/google/go-cmp/cmp"
3228 "github.com/stretchr/testify/require"
3329
3430 "vitess.io/vitess/go/mysql"
3531 "vitess.io/vitess/go/sqltypes"
3632 "vitess.io/vitess/go/test/endtoend/cluster"
33+ topoutils "vitess.io/vitess/go/test/endtoend/topotest/utils"
34+ "vitess.io/vitess/go/vt/log"
35+ "vitess.io/vitess/go/vt/topo"
3736)
3837
3938var (
@@ -221,6 +220,53 @@ func TestKeyspaceLocking(t *testing.T) {
221220 topoutils .WaitForBoolValue (t , & secondThreadLockAcquired , true )
222221}
223222
223+ // TestNamedLocking tests that named locking works as intended.
224+ func TestNamedLocking (t * testing.T ) {
225+ // Create topo server connection.
226+ ts , err := topo .OpenServer (* clusterInstance .TopoFlavorString (), clusterInstance .VtctldClientProcess .TopoGlobalAddress , clusterInstance .VtctldClientProcess .TopoGlobalRoot )
227+ require .NoError (t , err )
228+
229+ ctx := context .Background ()
230+ lockName := "TestNamedLocking"
231+ action := "Testing"
232+
233+ // Acquire a named lock.
234+ ctx , unlock , err := ts .LockName (ctx , lockName , action )
235+ require .NoError (t , err )
236+
237+ // Check that we can't reacquire it from the same context.
238+ _ , _ , err = ts .LockName (ctx , lockName , action )
239+ require .ErrorContains (t , err , fmt .Sprintf ("lock for named %s is already held" , lockName ))
240+
241+ // Check that CheckNameLocked doesn't return an error as we should still be
242+ // holding the lock.
243+ err = topo .CheckNameLocked (ctx , lockName )
244+ require .NoError (t , err )
245+
246+ // We'll now try to acquire the lock from a different goroutine.
247+ secondCallerAcquired := false
248+ go func () {
249+ _ , unlock , err := ts .LockName (context .Background (), lockName , action )
250+ defer unlock (& err )
251+ require .NoError (t , err )
252+ secondCallerAcquired = true
253+ }()
254+
255+ // Wait for some time and ensure that the second attempt at acquiring the lock
256+ // is blocked.
257+ time .Sleep (100 * time .Millisecond )
258+ require .False (t , secondCallerAcquired )
259+
260+ // Unlock the name.
261+ unlock (& err )
262+ // Check that we no longer have the named lock.
263+ err = topo .CheckNameLocked (ctx , lockName )
264+ require .ErrorContains (t , err , fmt .Sprintf ("named %s is not locked (no lockInfo in map)" , lockName ))
265+
266+ // Wait to see that the second goroutine WAS now able to acquire the named lock.
267+ topoutils .WaitForBoolValue (t , & secondCallerAcquired , true )
268+ }
269+
224270func execute (t * testing.T , conn * mysql.Conn , query string ) * sqltypes.Result {
225271 t .Helper ()
226272 qr , err := conn .ExecuteFetch (query , 1000 , true )
0 commit comments