diff options
author | Pavlo Strokov <pstrokov@gitlab.com> | 2022-12-18 20:28:27 +0300 |
---|---|---|
committer | Pavlo Strokov <pavlo@Pavlos-MacBook-Pro-5.local> | 2022-12-21 19:31:04 +0300 |
commit | e4c3c8db13a365e9d228eea6e33e0b25e31fd94d (patch) | |
tree | c910d22e600f555635fffa40480f6e1e5a17b9b9 | |
parent | 6f1d5675c7c55c6a2984736534a346c799e5913b (diff) |
command: Test the 'too many open files' error is returnedps-resource-exhausted-fd
We have statushandler middleware that changes status code of the RPC
depending on different conditions. One of such conditions is the
syscall.EMFILE error. This test is added to make sure this particular
error is returned when there is no more file descriptors available.
Otherwise, the statushandler middleware needs to be adjusted to catch
the proper error.
Part of: https://gitlab.com/gitlab-org/gitaly/-/issues/4688
-rw-r--r-- | internal/git/command_factory_test.go | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/internal/git/command_factory_test.go b/internal/git/command_factory_test.go index 3356fe467..a310164c5 100644 --- a/internal/git/command_factory_test.go +++ b/internal/git/command_factory_test.go @@ -12,9 +12,12 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "strings" + "syscall" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v15/internal/git" "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest" @@ -703,3 +706,58 @@ func TestFsckConfiguration(t *testing.T) { }) } } + +// TestExecCommandFactory_tooManyOpenFileDescriptors test exists to make sure the system +// returns an expected syscall.EMFILE error when there is a problem with FD as the +// middleware in internal/middleware/statushandler/statushandler.go heavily depends on it. +func TestExecCommandFactory_tooManyOpenFileDescriptors(t *testing.T) { + // Do not run this test with t.Parallel(). The test setup affects settings of the + // current process and may lead to other tests failures. + ctx := testhelper.Context(t) + + // setCur changes value of the Cur field of the Rlimit type. + // It is needed because on different OS this field represented by different types. + // Currently only by two: uint64, int64. That is why we use reflection to change the value. + setCur := func(t *testing.T, rl syscall.Rlimit, val int) syscall.Rlimit { + var cur interface{} = rl.Cur + switch cur.(type) { + case uint64: + reflect.ValueOf(&rl.Cur).Elem().SetUint(uint64(val)) + case int64: + reflect.ValueOf(&rl.Cur).Elem().SetInt(int64(val)) + default: + require.FailNowf(t, "code needs to be changed", "please add a new type: %T", rl.Cur) + } + return rl + } + + setOpenFilesLimit := func(t *testing.T, limit int) { + // This is a flag for the resource to limit. In that case: open file descriptors. + const flag = syscall.RLIMIT_NOFILE + var rlim syscall.Rlimit + require.NoError(t, syscall.Getrlimit(flag, &rlim)) + t.Cleanup(func() { + require.NoError(t, syscall.Setrlimit(flag, &rlim)) + }) + newRLimit := setCur(t, rlim, limit) + require.NoError(t, syscall.Setrlimit(flag, &newRLimit)) + } + + cfg, repo, _ := testcfg.BuildWithRepo(t) + factory, finish, err := git.NewExecCommandFactory(cfg) + require.NoError(t, err) + t.Cleanup(finish) + + setOpenFilesLimit(t, 10) + + // It is enough to run whatever command usually as the limit is really low. + cmd, err := factory.New(ctx, repo, git.Command{ + Name: "show", + Args: []string{"HEAD"}, + }) + if !assert.Error(t, err) { + _ = cmd.Wait() // we don't care about an error here as it shouldn't happen + return + } + require.ErrorIs(t, err, syscall.EMFILE) // too many open files +} |