github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/locks_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package function 16 17 import ( 18 "testing" 19 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 ) 25 26 const ( 27 alreadyLocked = "already_locked" 28 unlocked = "unlocked" 29 ) 30 31 func TestGetLock(t *testing.T) { 32 ls := sql.NewLockSubsystem() 33 var fn sql.CreateFunc2Args = CreateNewGetLock(ls) 34 tf := NewTestFactory(fn) 35 36 user0 := sql.NewEmptyContext() 37 err := ls.Lock(user0, alreadyLocked, 0) 38 require.NoError(t, err) 39 err = ls.Lock(user0, unlocked, 0) 40 require.NoError(t, err) 41 err = ls.Unlock(user0, unlocked) 42 require.NoError(t, err) 43 44 user1 := sql.NewEmptyContext() 45 tf.AddSucceeding(nil, nil, nil) 46 tf.AddSucceeding(nil, "nil_param_test", nil) 47 tf.AddSucceeding(nil, nil, 0) 48 tf.AddSucceeding(int8(1), "new_lock", 0) 49 tf.AddSucceeding(int8(1), unlocked, 0) 50 tf.AddSucceeding(int8(0), alreadyLocked, 0) 51 tf.AddFailing(0, 0) 52 tf.Test(t, user1, nil) 53 } 54 55 func TestLockIsFree(t *testing.T) { 56 ls := sql.NewLockSubsystem() 57 isFreeLock := NewIsFreeLock(ls) 58 tf := NewTestFactory(isFreeLock) 59 60 user0 := sql.NewEmptyContext() 61 err := ls.Lock(user0, alreadyLocked, 0) 62 require.NoError(t, err) 63 err = ls.Lock(user0, unlocked, 0) 64 require.NoError(t, err) 65 err = ls.Unlock(user0, unlocked) 66 require.NoError(t, err) 67 68 user1 := sql.NewEmptyContext() 69 tf.AddSucceeding(nil, nil) 70 tf.AddSucceeding(int8(1), "new_lock") 71 tf.AddSucceeding(int8(1), unlocked) 72 tf.AddSucceeding(int8(0), alreadyLocked) 73 tf.AddFailing(0) 74 tf.Test(t, user1, nil) 75 } 76 77 func TestLockIsUsed(t *testing.T) { 78 ls := sql.NewLockSubsystem() 79 isUsed := NewIsUsedLock(ls) 80 tf := NewTestFactory(isUsed) 81 82 user0 := sql.NewEmptyContext() 83 err := ls.Lock(user0, alreadyLocked, 0) 84 require.NoError(t, err) 85 err = ls.Lock(user0, unlocked, 0) 86 require.NoError(t, err) 87 err = ls.Unlock(user0, unlocked) 88 require.NoError(t, err) 89 90 user1 := sql.NewEmptyContext() 91 tf.AddSucceeding(nil, nil) 92 tf.AddSucceeding(nil, "new_lock") 93 tf.AddSucceeding(nil, unlocked) 94 tf.AddSucceeding(user0.ID(), alreadyLocked) 95 tf.AddFailing(0) 96 tf.Test(t, user1, nil) 97 } 98 99 func TestReleaseLock(t *testing.T) { 100 ls := sql.NewLockSubsystem() 101 releaseLock := NewReleaseLock(ls) 102 tf := NewTestFactory(releaseLock) 103 104 user0 := sql.NewEmptyContext() 105 err := ls.Lock(user0, alreadyLocked, 0) 106 require.NoError(t, err) 107 err = ls.Lock(user0, unlocked, 0) 108 require.NoError(t, err) 109 err = ls.Unlock(user0, unlocked) 110 require.NoError(t, err) 111 112 tf.AddSucceeding(nil, nil) 113 tf.AddSucceeding(int8(1), alreadyLocked) 114 tf.AddSucceeding(int8(0), unlocked) 115 tf.AddSucceeding(nil, "doesnt_exist") 116 tf.AddFailing(0) 117 tf.Test(t, user0, nil) 118 } 119 120 func TestReleaseAllLocks(t *testing.T) { 121 ls := sql.NewLockSubsystem() 122 123 user0 := sql.NewEmptyContext() 124 err := ls.Lock(user0, "lock0", 0) 125 require.NoError(t, err) 126 err = ls.Lock(user0, "lock1", 0) 127 require.NoError(t, err) 128 err = ls.Lock(user0, "lock2", 0) 129 require.NoError(t, err) 130 err = ls.Lock(user0, "lock2", 0) 131 require.NoError(t, err) 132 err = ls.Lock(user0, "lock2", 0) 133 require.NoError(t, err) 134 135 count := 0 136 err = user0.IterLocks(func(name string) error { 137 count++ 138 return nil 139 }) 140 require.NoError(t, err) 141 assert.Equal(t, 3, count) 142 143 state, owner := ls.GetLockState("lock0") 144 assert.Equal(t, sql.LockInUse, state) 145 assert.Equal(t, user0.ID(), owner) 146 ls.GetLockState("lock1") 147 assert.Equal(t, sql.LockInUse, state) 148 assert.Equal(t, user0.ID(), owner) 149 ls.GetLockState("lock2") 150 assert.Equal(t, sql.LockInUse, state) 151 assert.Equal(t, user0.ID(), owner) 152 153 _, err = releaseAllLocksForLS(ls)(user0, nil) 154 require.NoError(t, err) 155 156 count = 0 157 err = user0.IterLocks(func(name string) error { 158 count++ 159 return nil 160 }) 161 require.NoError(t, err) 162 assert.Equal(t, 3, count) 163 164 state, owner = ls.GetLockState("lock0") 165 assert.Equal(t, sql.LockFree, state) 166 assert.Equal(t, uint32(0), owner) 167 ls.GetLockState("lock1") 168 assert.Equal(t, sql.LockFree, state) 169 assert.Equal(t, uint32(0), owner) 170 ls.GetLockState("lock2") 171 assert.Equal(t, sql.LockFree, state) 172 assert.Equal(t, uint32(0), owner) 173 } 174 175 // releaseAllLocksForLS returns the logic to execute when the sql function release_all_locks is executed 176 func releaseAllLocksForLS(ls *sql.LockSubsystem) func(*sql.Context, sql.Row) (interface{}, error) { 177 return func(ctx *sql.Context, _ sql.Row) (interface{}, error) { 178 return ls.ReleaseAll(ctx) 179 } 180 }