Merge pull request #4022 from MichaelEischer/race-checker

CI: Run the golang race checker
This commit is contained in:
Michael Eischer 2022-11-26 12:13:50 +01:00 committed by GitHub
commit f115d64634
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 28 additions and 5 deletions

View file

@ -37,6 +37,13 @@ jobs:
check_changelog: true check_changelog: true
install_verb: install install_verb: install
- job_name: Linux (race)
go: 1.19.x
os: ubuntu-latest
test_fuse: true
test_opts: "-race"
install_verb: install
- job_name: Linux - job_name: Linux
go: 1.18.x go: 1.18.x
os: ubuntu-latest os: ubuntu-latest
@ -152,7 +159,7 @@ jobs:
env: env:
RESTIC_TEST_FUSE: ${{ matrix.test_fuse }} RESTIC_TEST_FUSE: ${{ matrix.test_fuse }}
run: | run: |
go test -cover ./... go test -cover ${{matrix.test_opts}} ./...
- name: Test cloud backends - name: Test cloud backends
env: env:

View file

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sync"
"testing" "testing"
"time" "time"
@ -54,7 +55,8 @@ func waitForMount(t testing.TB, dir string) {
t.Errorf("subdir %q of dir %s never appeared", mountTestSubdir, dir) t.Errorf("subdir %q of dir %s never appeared", mountTestSubdir, dir)
} }
func testRunMount(t testing.TB, gopts GlobalOptions, dir string) { func testRunMount(t testing.TB, gopts GlobalOptions, dir string, wg *sync.WaitGroup) {
defer wg.Done()
opts := MountOptions{ opts := MountOptions{
TimeTemplate: time.RFC3339, TimeTemplate: time.RFC3339,
} }
@ -87,8 +89,11 @@ func listSnapshots(t testing.TB, dir string) []string {
func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Repository, mountpoint, repodir string, snapshotIDs restic.IDs, expectedSnapshotsInFuseDir int) { func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Repository, mountpoint, repodir string, snapshotIDs restic.IDs, expectedSnapshotsInFuseDir int) {
t.Logf("checking for %d snapshots: %v", len(snapshotIDs), snapshotIDs) t.Logf("checking for %d snapshots: %v", len(snapshotIDs), snapshotIDs)
go testRunMount(t, global, mountpoint) var wg sync.WaitGroup
wg.Add(1)
go testRunMount(t, global, mountpoint, &wg)
waitForMount(t, mountpoint) waitForMount(t, mountpoint)
defer wg.Wait()
defer testRunUmount(t, global, mountpoint) defer testRunUmount(t, global, mountpoint)
if !snapshotsDirExists(t, mountpoint) { if !snapshotsDirExists(t, mountpoint) {

View file

@ -26,6 +26,7 @@ import (
// A lock must be refreshed regularly to not be considered stale, this must be // A lock must be refreshed regularly to not be considered stale, this must be
// triggered by regularly calling Refresh. // triggered by regularly calling Refresh.
type Lock struct { type Lock struct {
lock sync.Mutex
Time time.Time `json:"time"` Time time.Time `json:"time"`
Exclusive bool `json:"exclusive"` Exclusive bool `json:"exclusive"`
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
@ -195,6 +196,8 @@ var StaleLockTimeout = 30 * time.Minute
// older than 30 minutes or if it was created on the current machine and the // older than 30 minutes or if it was created on the current machine and the
// process isn't alive any more. // process isn't alive any more.
func (l *Lock) Stale() bool { func (l *Lock) Stale() bool {
l.lock.Lock()
defer l.lock.Unlock()
debug.Log("testing if lock %v for process %d is stale", l, l.PID) debug.Log("testing if lock %v for process %d is stale", l, l.PID)
if time.Since(l.Time) > StaleLockTimeout { if time.Since(l.Time) > StaleLockTimeout {
debug.Log("lock is stale, timestamp is too old: %v\n", l.Time) debug.Log("lock is stale, timestamp is too old: %v\n", l.Time)
@ -229,12 +232,17 @@ func (l *Lock) Stale() bool {
// timestamp. Afterwards the old lock is removed. // timestamp. Afterwards the old lock is removed.
func (l *Lock) Refresh(ctx context.Context) error { func (l *Lock) Refresh(ctx context.Context) error {
debug.Log("refreshing lock %v", l.lockID) debug.Log("refreshing lock %v", l.lockID)
l.lock.Lock()
l.Time = time.Now() l.Time = time.Now()
l.lock.Unlock()
id, err := l.createLock(ctx) id, err := l.createLock(ctx)
if err != nil { if err != nil {
return err return err
} }
l.lock.Lock()
defer l.lock.Unlock()
debug.Log("new lock ID %v", id) debug.Log("new lock ID %v", id)
oldLockID := l.lockID oldLockID := l.lockID
l.lockID = &id l.lockID = &id
@ -242,7 +250,10 @@ func (l *Lock) Refresh(ctx context.Context) error {
return l.repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: oldLockID.String()}) return l.repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: oldLockID.String()})
} }
func (l Lock) String() string { func (l *Lock) String() string {
l.lock.Lock()
defer l.lock.Unlock()
text := fmt.Sprintf("PID %d on %s by %s (UID %d, GID %d)\nlock was created at %s (%s ago)\nstorage ID %v", text := fmt.Sprintf("PID %d on %s by %s (UID %d, GID %d)\nlock was created at %s (%s ago)\nstorage ID %v",
l.PID, l.Hostname, l.Username, l.UID, l.GID, l.PID, l.Hostname, l.Username, l.UID, l.GID,
l.Time.Format("2006-01-02 15:04:05"), time.Since(l.Time), l.Time.Format("2006-01-02 15:04:05"), time.Since(l.Time),

View file

@ -29,7 +29,7 @@ func uidGidInt(u *user.User) (uid, gid uint32, err error) {
// checkProcess will check if the process retaining the lock // checkProcess will check if the process retaining the lock
// exists and responds to SIGHUP signal. // exists and responds to SIGHUP signal.
// Returns true if the process exists and responds. // Returns true if the process exists and responds.
func (l Lock) processExists() bool { func (l *Lock) processExists() bool {
proc, err := os.FindProcess(l.PID) proc, err := os.FindProcess(l.PID)
if err != nil { if err != nil {
debug.Log("error searching for process %d: %v\n", l.PID, err) debug.Log("error searching for process %d: %v\n", l.PID, err)