mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 08:35:17 +00:00
107 lines
3.0 KiB
Go
107 lines
3.0 KiB
Go
|
// Copyright 2014 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||
|
// of this source code is governed by a BSD-style license that can be found in
|
||
|
// the LICENSE file.
|
||
|
|
||
|
package vfs_test
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"flag"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/cockroachdb/pebble/vfs"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
var lockFilename = flag.String("lockfile", "", "File to lock. A non-empty value implies a child process.")
|
||
|
|
||
|
func spawn(prog, filename string) ([]byte, error) {
|
||
|
return exec.Command(prog, "-lockfile", filename, "-test.v",
|
||
|
"-test.run=TestLock$").CombinedOutput()
|
||
|
}
|
||
|
|
||
|
// TestLock locks a file, spawns a second process that attempts to grab the
|
||
|
// lock to verify it fails.
|
||
|
// Then it closes the lock, and spawns a third copy to verify it can be
|
||
|
// relocked.
|
||
|
func TestLock(t *testing.T) {
|
||
|
child := *lockFilename != ""
|
||
|
var filename string
|
||
|
if child {
|
||
|
filename = *lockFilename
|
||
|
} else {
|
||
|
f, err := os.CreateTemp("", "golang-pebble-db-testlock-")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
filename = f.Name()
|
||
|
// NB: On Windows, locking will fail if the file is already open by the
|
||
|
// current process, so we close the lockfile here.
|
||
|
require.NoError(t, f.Close())
|
||
|
defer os.Remove(filename)
|
||
|
}
|
||
|
|
||
|
// Avoid truncating an existing, non-empty file.
|
||
|
fi, err := os.Stat(filename)
|
||
|
if err == nil && fi.Size() != 0 {
|
||
|
t.Fatalf("The file %s is not empty", filename)
|
||
|
}
|
||
|
|
||
|
t.Logf("Locking: %s", filename)
|
||
|
lock, err := vfs.Default.Lock(filename)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Could not lock %s: %v", filename, err)
|
||
|
}
|
||
|
|
||
|
if !child {
|
||
|
t.Logf("Spawning child, should fail to grab lock.")
|
||
|
out, err := spawn(os.Args[0], filename)
|
||
|
if err == nil {
|
||
|
t.Fatalf("Attempt to grab open lock should have failed.\n%s", out)
|
||
|
}
|
||
|
if !bytes.Contains(out, []byte("Could not lock")) {
|
||
|
t.Fatalf("Child failed with unexpected output: %s", out)
|
||
|
}
|
||
|
t.Logf("Child failed to grab lock as expected.")
|
||
|
}
|
||
|
|
||
|
t.Logf("Unlocking %s", filename)
|
||
|
if err := lock.Close(); err != nil {
|
||
|
t.Fatalf("Could not unlock %s: %v", filename, err)
|
||
|
}
|
||
|
|
||
|
if !child {
|
||
|
t.Logf("Spawning child, should successfully grab lock.")
|
||
|
if out, err := spawn(os.Args[0], filename); err != nil {
|
||
|
t.Fatalf("Attempt to re-open lock should have succeeded: %v\n%s",
|
||
|
err, out)
|
||
|
}
|
||
|
t.Logf("Child grabbed lock.")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestLockSameProcess(t *testing.T) {
|
||
|
f, err := os.CreateTemp("", "pebble-testlocksameprocess-")
|
||
|
require.NoError(t, err)
|
||
|
filename := f.Name()
|
||
|
|
||
|
// NB: On Windows, locking will fail if the file is already open by the
|
||
|
// current process, so we close the lockfile here.
|
||
|
require.NoError(t, f.Close())
|
||
|
defer os.Remove(filename)
|
||
|
|
||
|
lock1, err := vfs.Default.Lock(filename)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
// Locking the file again from within the same process should fail.
|
||
|
// On Unix, Lock should detect the file in the global map of
|
||
|
// process-locked files.
|
||
|
// On Windows, locking will fail since the file is already open by the
|
||
|
// current process.
|
||
|
_, err = vfs.Default.Lock(filename)
|
||
|
require.Error(t, err)
|
||
|
|
||
|
require.NoError(t, lock1.Close())
|
||
|
}
|