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  }