Add fileleak task
This commit is contained in:
parent
b6f50e3aba
commit
fc2e047ed1
3 changed files with 114 additions and 0 deletions
23
fileleak/README.md
Normal file
23
fileleak/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# fileleak
|
||||
|
||||
Реализуйте библиотеку для поиска утечек файлов в тестах.
|
||||
|
||||
Библиотека содержит единственную функцию - `VerifyNone`. Пользователь должен вызвать эту функцию в начале своего теста.
|
||||
|
||||
Библиотека смотрит на все открытые файлы процесса в начале и в конце теста. Если в конце теста будут находятся открытые файлы,
|
||||
которые не были открыты на момент старта теста, то библиотека фейлит весь тест.
|
||||
|
||||
Эта задача будет корректно работать только на `linux`. Чтобы узнать открытые файлы процесса, нужно прочитать директорию
|
||||
`/proc/self/fd`. Эта директория содержит символические ссылки. Именем ссылки является номер файлового дескриптора, а значением
|
||||
ссылки является какое-то текстовое описание открытого файла. Значение ссылки можно прочитать, используя `os.Readlink`.
|
||||
|
||||
```bash
|
||||
prime@bee ~/C/shad-go> ls -lah /proc/self/fd
|
||||
total 0
|
||||
dr-x------ 2 prime prime 0 мар 12 19:44 ./
|
||||
dr-xr-xr-x 9 prime prime 0 мар 12 19:44 ../
|
||||
lrwx------ 1 prime prime 64 мар 12 19:44 0 -> /dev/pts/7
|
||||
lrwx------ 1 prime prime 64 мар 12 19:44 1 -> /dev/pts/7
|
||||
lrwx------ 1 prime prime 64 мар 12 19:44 2 -> /dev/pts/7
|
||||
lr-x------ 1 prime prime 64 мар 12 19:44 3 -> /proc/871308/fd/
|
||||
```
|
12
fileleak/fileleak.go
Normal file
12
fileleak/fileleak.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
// +build !solution
|
||||
|
||||
package fileleak
|
||||
|
||||
type testingT interface {
|
||||
Errorf(msg string, args ...interface{})
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
func VerifyNone(t testingT) {
|
||||
panic("implement me")
|
||||
}
|
79
fileleak/fileleak_test.go
Normal file
79
fileleak/fileleak_test.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package fileleak_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"gitlab.com/slon/shad-go/fileleak"
|
||||
)
|
||||
|
||||
type fakeT struct {
|
||||
failed bool
|
||||
buffer bytes.Buffer
|
||||
cleanup []func()
|
||||
}
|
||||
|
||||
func (f *fakeT) Errorf(msg string, args ...interface{}) {
|
||||
f.failed = true
|
||||
fmt.Fprintf(&f.buffer, msg, args...)
|
||||
}
|
||||
|
||||
func (f *fakeT) Cleanup(cb func()) {
|
||||
f.cleanup = append([]func(){cb}, f.cleanup...)
|
||||
}
|
||||
|
||||
func checkLeak(t *testing.T, shouldDetect bool, leaker func()) {
|
||||
var fake fakeT
|
||||
fileleak.VerifyNone(&fake)
|
||||
leaker()
|
||||
for _, cb := range fake.cleanup {
|
||||
cb()
|
||||
}
|
||||
|
||||
switch {
|
||||
case shouldDetect && !fake.failed:
|
||||
t.Errorf("fileleak didn't detect a leak")
|
||||
case !shouldDetect && fake.failed:
|
||||
t.Errorf("fileleak detected a leak when there is none:\n%s", fake.buffer.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileLeak_OpenFile(t *testing.T) {
|
||||
var f *os.File
|
||||
checkLeak(t, true, func() {
|
||||
var err error
|
||||
f, err = os.Open("/proc/self/exe")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
if f != nil {
|
||||
_ = f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileLeak_AlwaysOpenFile(t *testing.T) {
|
||||
f, err := os.Open("/proc/self/exe")
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
checkLeak(t, false, func() {})
|
||||
}
|
||||
|
||||
func TestFileLeak_ReopenFile(t *testing.T) {
|
||||
f, err := os.Open("/proc/self/exe")
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
checkLeak(t, true, func() {
|
||||
_ = f.Close()
|
||||
|
||||
ff, err := ioutil.TempFile("", "")
|
||||
require.NoError(t, err)
|
||||
f = ff
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue