package filemutex
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
func TestLockUnlock(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
err = m.Lock()
require.NoError(t, err)
err = m.Unlock()
require.NoError(t, err)
}
func TestTryLockUnlock(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
m2, err := New(path)
require.NoError(t, err)
err = m.Lock()
require.NoError(t, err)
err = m2.TryLock()
require.Equal(t, AlreadyLocked, err)
err = m.Unlock()
require.NoError(t, err)
err = m2.TryLock()
require.NoError(t, err)
}
func TestRLockUnlock(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
err = m.RLock()
require.NoError(t, err)
err = m.RUnlock()
require.NoError(t, err)
}
func TestClose(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
m.Lock()
m.Close()
}
func TestOnlyClose(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
require.NoError(t, m.Close())
}
func TestLockErrorsAreRecoverable(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
// muck with the internal state in order to cause an error
oldfd := m.fd
m.fd = 99999
// trigger an error
err = m.Lock()
require.Error(t, err)
// restore a sane internal state
m.fd = oldfd
// this would hang if we hadn't Unlock()ed in the Lock error branch
err = m.Lock()
require.NoError(t, err)
// clean up
err = m.Unlock()
require.NoError(t, err)
}
func TestUnlockErrorsAreRecoverable(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
err = m.Lock()
require.NoError(t, err)
// muck with the internal state in order to cause an error
oldfd := m.fd
m.fd = 99999
// trigger an error
err = m.Unlock()
require.Error(t, err)
// restore a sane internal state
m.fd = oldfd
// this would crash if we the mutex were unlocked in the error branch
err = m.Unlock()
require.NoError(t, err)
}
func TestRLockErrorsAreRecoverable(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
// muck with the internal state in order to cause an error
oldfd := m.fd
m.fd = 99999
// trigger an error
err = m.RLock()
require.Error(t, err)
// restore a sane internal state
m.fd = oldfd
// this would hang if we hadn't Unlock()ed in the RLock error branch
err = m.Lock()
require.NoError(t, err)
// clean up
err = m.Unlock()
require.NoError(t, err)
}
func TestRUnlockErrorsAreRecoverable(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "x")
m, err := New(path)
require.NoError(t, err)
err = m.RLock()
require.NoError(t, err)
// muck with the internal state in order to cause an error
oldfd := m.fd
m.fd = 99999
// trigger an error
err = m.RUnlock()
require.Error(t, err)
// restore a sane internal state
m.fd = oldfd
// this would crash if we the mutex were unlocked in the error branch
err = m.RUnlock()
require.NoError(t, err)
}