// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may not // use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific language governing // permissions and limitations under the License. package filelock import ( "fmt" "os" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" ) func TestSerialLocking(t *testing.T) { lockPath := "lock-file.TestSerialLocking.tmp" ownerId1 := "1001" ownerId2 := "1002" timeoutSeconds := 1 var err error var locked bool var hadLock bool // First, clean up os.Remove(lockPath) // First lock locked, err = LockFile(lockPath, ownerId1, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) hadLock, err = UnlockFile(lockPath, ownerId1) assert.NoError(t, err) assert.Equal(t, true, hadLock) // Second lock, same owner locked, err = LockFile(lockPath, ownerId1, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) hadLock, err = UnlockFile(lockPath, ownerId1) assert.NoError(t, err) assert.Equal(t, true, hadLock) // Third lock, different owner locked, err = LockFile(lockPath, ownerId2, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) hadLock, err = UnlockFile(lockPath, ownerId2) assert.NoError(t, err) assert.Equal(t, true, hadLock) // Last, clean up again os.Remove(lockPath) } func TestInterlappingLocking(t *testing.T) { lockPath := "lock-file.TestInterlappingLocking.tmp" ownerId1 := "1001" ownerId2 := "1002" timeoutSeconds := 1 var err error var locked bool var hadLock bool // First, clean up os.Remove(lockPath) // First lock locked, err = LockFile(lockPath, ownerId1, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) // Second lock, different owner - should fail locked, err = LockFile(lockPath, ownerId2, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, false, locked) hadLock, err = UnlockFile(lockPath, ownerId1) assert.NoError(t, err) assert.Equal(t, true, hadLock) // Last, clean up again os.Remove(lockPath) } func TestLockingTimeout(t *testing.T) { lockPath := "lock-file.TestInterlappingLocking.tmp" ownerId1 := "1001" ownerId2 := "1002" timeoutSeconds := 1 var err error var locked bool var hadLock bool // First, clean up os.Remove(lockPath) // First lock locked, err = LockFile(lockPath, ownerId1, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) time.Sleep(1500 * time.Millisecond) // Second lock, different owner - should succeed, since lock is timed out. locked, err = LockFile(lockPath, ownerId2, timeoutSeconds) assert.NoError(t, err) assert.Equal(t, true, locked) // First unlock, should fail, since lock timed out. hadLock, err = UnlockFile(lockPath, ownerId1) assert.NoError(t, err) assert.Equal(t, false, hadLock) hadLock, err = UnlockFile(lockPath, ownerId2) assert.NoError(t, err) assert.Equal(t, true, hadLock) // Last, clean up again os.Remove(lockPath) } func TestParallelLocking(t *testing.T) { lockPath := "lock-file.TestParallelLocking.tmp" timeoutSeconds := 100 // First, clean up os.Remove(lockPath) N := 1000 var wg sync.WaitGroup wg.Add(N) var lockCountAtomic int32 = 0 for i := 0; i < N; i++ { go func(id int) { defer wg.Done() ownerId := fmt.Sprintf("ownerId-%d", id) // Only one thread should get the lock. locked, err := LockFile(lockPath, ownerId, timeoutSeconds) assert.NoError(t, err) if locked { atomic.AddInt32(&lockCountAtomic, 1) } fmt.Printf("gorouting completed %v\n", ownerId) }(i) } wg.Wait() lockCount := int(atomic.LoadInt32(&lockCountAtomic)) assert.Equal(t, 1, lockCount) // Last, clean up again os.Remove(lockPath) }