Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/20251015114355.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:gear: `[parallelisation]` Report the context cancellation cause in the related error to provide more context
37 changes: 0 additions & 37 deletions utils/filesystem/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"context"
"fmt"
"io"
"net"
"os"
"path/filepath"
"reflect"
Expand All @@ -23,7 +22,6 @@ import (
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"

"github.com/ARM-software/golang-utils/utils/collection"
"github.com/ARM-software/golang-utils/utils/commonerrors"
Expand Down Expand Up @@ -549,9 +547,6 @@ func TestConvertPaths(t *testing.T) {
}

func TestIsFile(t *testing.T) {
if platform.IsWindows() {
t.Skip("Windows doesn't have features such as named pipes or unix sockets")
}
for _, fsType := range FileSystemTypes {
t.Run(fmt.Sprint(fsType), func(t *testing.T) {
fs := NewFs(fsType)
Expand All @@ -567,38 +562,6 @@ func TestIsFile(t *testing.T) {
assert.True(t, b)
})

t.Run("special file", func(t *testing.T) {
if fsType == InMemoryFS {
t.Skip("In-memory file system won't have hardware devices or special files")
}

b, err := fs.IsFile("/dev/null")
require.NoError(t, err)
assert.True(t, b)

fifoPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(fifoPath) }()
err = unix.Mkfifo(fifoPath, 0666)
require.NoError(t, err)
b, err = fs.IsFile(fifoPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(fifoPath)
require.NoError(t, err)

socketPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(socketPath) }()
l, err := net.Listen("unix", socketPath)
require.NoError(t, err)
defer func() { _ = l.Close() }()
b, err = fs.IsFile(socketPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(socketPath)
require.NoError(t, err)
})
})
}
}
Expand Down
68 changes: 68 additions & 0 deletions utils/filesystem/files_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//go:build !windows
// +build !windows

package filesystem

import (
"fmt"
"net"
"path/filepath"
"testing"

"github.com/go-faker/faker/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
)

func TestIsUnixFile(t *testing.T) {
for _, fsType := range FileSystemTypes {
t.Run(fmt.Sprint(fsType), func(t *testing.T) {
fs := NewFs(fsType)

tmpDir := t.TempDir()

t.Run("normal file", func(t *testing.T) {
filePath := filepath.Join(tmpDir, faker.Word())
err := fs.Touch(filePath)
require.NoError(t, err)
b, err := fs.IsFile(filePath)
require.NoError(t, err)
assert.True(t, b)
})

t.Run("special file", func(t *testing.T) {
if fsType == InMemoryFS {
t.Skip("In-memory file system won't have hardware devices or special files")
}

b, err := fs.IsFile("/dev/null")
require.NoError(t, err)
assert.True(t, b)

fifoPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(fifoPath) }()
err = unix.Mkfifo(fifoPath, 0666)
require.NoError(t, err)
b, err = fs.IsFile(fifoPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(fifoPath)
require.NoError(t, err)

socketPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(socketPath) }()
l, err := net.Listen("unix", socketPath)
require.NoError(t, err)
defer func() { _ = l.Close() }()
b, err = fs.IsFile(socketPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(socketPath)
require.NoError(t, err)
})
})
}
}
9 changes: 5 additions & 4 deletions utils/filesystem/lockfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"go.uber.org/goleak"

"github.com/ARM-software/golang-utils/utils/commonerrors"
"github.com/ARM-software/golang-utils/utils/commonerrors/errortest"
)

var (
Expand Down Expand Up @@ -361,18 +362,18 @@ func TestLockConcurrentSafeguard(t *testing.T) {
// FIXME it was noticed that there could be some race conditions happening in the in-memory file system
// see https://github.com/spf13/afero/issues/298
if err1 != nil {
require.Equal(t0, expectedError, err1)
errortest.RequireError(t0, err1, expectedError)
}
if err2 != nil {
require.Equal(t0, expectedError, err2)
errortest.RequireError(t0, err2, expectedError)
}
} else {
require.NotEqual(t0, err1, err2)
if err1 == nil {
require.Equal(t0, expectedError, err2)
errortest.RequireError(t0, err2, expectedError)
}
if err2 == nil {
require.Equal(t0, expectedError, err1)
errortest.RequireError(t0, err1, expectedError)
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion utils/parallelisation/contextual.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import (

// DetermineContextError determines what the context error is if any.
func DetermineContextError(ctx context.Context) error {
return commonerrors.ConvertContextError(ctx.Err())
err := commonerrors.ConvertContextError(ctx.Err())
if commonerrors.Any(err, nil) {
return err
}
return commonerrors.WrapError(err, context.Cause(ctx), "")
}

type ContextualFunc func(ctx context.Context) error
Expand Down
37 changes: 37 additions & 0 deletions utils/parallelisation/contextual_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package parallelisation

import (
"context"
"errors"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ARM-software/golang-utils/utils/commonerrors"
Expand Down Expand Up @@ -49,3 +52,37 @@ func TestForEach(t *testing.T) {
require.NoError(t, ForEach(context.Background(), WithOptions(Workers(5), JoinErrors), WrapCancelToContextualFunc(cancelFunc), WrapCancelToContextualFunc(cancelFunc), WrapCancelToContextualFunc(cancelFunc)))
})
}

func TestDetermineContextError(t *testing.T) {
t.Run("normal", func(t *testing.T) {
require.NoError(t, DetermineContextError(context.Background()))
})
t.Run("cancellation", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
require.NoError(t, DetermineContextError(ctx))
cancel()
err := DetermineContextError(ctx)
errortest.AssertError(t, err, commonerrors.ErrCancelled)
})
t.Run("cancellation with cause", func(t *testing.T) {
cause := errors.New("a cause")
ctx, cancel := context.WithCancelCause(context.Background())
defer cancel(cause)
require.NoError(t, DetermineContextError(ctx))
cancel(cause)
err := DetermineContextError(ctx)
errortest.AssertError(t, err, commonerrors.ErrCancelled)
errortest.AssertErrorDescription(t, err, cause.Error())
})
t.Run("cancellation with timeout cause", func(t *testing.T) {
cause := errors.New("a cause")
ctx, cancel := context.WithTimeoutCause(context.Background(), 5*time.Second, cause)
defer cancel()
require.NoError(t, DetermineContextError(ctx))
cancel()
err := DetermineContextError(ctx)
errortest.RequireError(t, err, commonerrors.ErrCancelled)
assert.NotContains(t, err.Error(), cause.Error()) // the timeout did not take effect and a cancellation was performed instead so the cause is not passed through
})
}
Loading