99 lines
2.3 KiB
Go
99 lines
2.3 KiB
Go
package flock_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/cli/cli/v2/internal/flock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestTryLock(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setup func(t *testing.T) string // returns lock path
|
|
wantErr error
|
|
verify func(t *testing.T, f *os.File)
|
|
}{
|
|
{
|
|
name: "acquires lock and returns writable file handle",
|
|
setup: func(t *testing.T) string {
|
|
return filepath.Join(t.TempDir(), "test.lock")
|
|
},
|
|
verify: func(t *testing.T, f *os.File) {
|
|
t.Helper()
|
|
_, err := f.WriteString("hello")
|
|
require.NoError(t, err)
|
|
_, err = f.Seek(0, 0)
|
|
require.NoError(t, err)
|
|
buf := make([]byte, 5)
|
|
n, err := f.Read(buf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "hello", string(buf[:n]))
|
|
},
|
|
},
|
|
{
|
|
name: "creates lock file if it does not exist",
|
|
setup: func(t *testing.T) string {
|
|
dir := filepath.Join(t.TempDir(), "subdir")
|
|
require.NoError(t, os.MkdirAll(dir, 0o755))
|
|
return filepath.Join(dir, "new.lock")
|
|
},
|
|
verify: func(t *testing.T, f *os.File) {
|
|
t.Helper()
|
|
_, err := os.Stat(f.Name())
|
|
assert.NoError(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "second lock on same path returns ErrLocked",
|
|
setup: func(t *testing.T) string {
|
|
lockPath := filepath.Join(t.TempDir(), "contended.lock")
|
|
_, unlock, err := flock.TryLock(lockPath)
|
|
require.NoError(t, err)
|
|
t.Cleanup(unlock)
|
|
return lockPath
|
|
},
|
|
wantErr: flock.ErrLocked,
|
|
},
|
|
{
|
|
name: "lock succeeds after unlock",
|
|
setup: func(t *testing.T) string {
|
|
lockPath := filepath.Join(t.TempDir(), "reuse.lock")
|
|
_, unlock, err := flock.TryLock(lockPath)
|
|
require.NoError(t, err)
|
|
unlock()
|
|
return lockPath
|
|
},
|
|
},
|
|
{
|
|
name: "fails on non-existent directory",
|
|
setup: func(t *testing.T) string {
|
|
return filepath.Join(t.TempDir(), "no", "such", "dir", "test.lock")
|
|
},
|
|
wantErr: os.ErrNotExist,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
lockPath := tt.setup(t)
|
|
|
|
f, unlock, err := flock.TryLock(lockPath)
|
|
if tt.wantErr != nil {
|
|
require.ErrorIs(t, err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, f)
|
|
defer unlock()
|
|
|
|
if tt.verify != nil {
|
|
tt.verify(t, f)
|
|
}
|
|
})
|
|
}
|
|
}
|